The response has been limited to 50k tokens of the smallest files in the repo. You can remove this limitation by removing the max tokens filter.
├── .gitattributes
├── .gitignore
├── .travis.yml
├── Godeps
    ├── Godeps.json
    └── Readme
├── LICENSE.md
├── README.md
├── app.go
├── callbacks.go
├── cmd
    └── gallium-bundle
    │   ├── bindata.go
    │   ├── bundle.go
    │   ├── iconset.go
    │   └── info.plist.tpl
├── cocoa.go
├── dist
    ├── Gallium.framework
    │   ├── Frameworks
    │   ├── Gallium
    │   ├── Libraries
    │   ├── Resources
    │   └── Versions
    │   │   ├── A
    │   │       ├── Gallium
    │   │       ├── Libraries
    │   │       │   ├── ffmpegsumo.so
    │   │       │   └── libchromiumcontent.dylib
    │   │       └── Resources
    │   │       │   ├── MainMenu.nib
    │   │       │   ├── WindowController.nib
    │   │       │   ├── content_shell.pak
    │   │       │   └── icudtl.dat
    │   │   └── Current
    └── include
    │   └── gallium
    │       ├── browser.h
    │       ├── cocoa.h
    │       ├── core.h
    │       ├── globalshortcut.h
    │       └── screen.h
├── examples
    ├── controller
    │   └── controller.go
    ├── desktop-notification
    │   ├── bindata.go
    │   ├── gopher.png
    │   └── notification.go
    ├── frameless
    │   └── frameless.go
    ├── keys
    │   └── keys.go
    ├── menu
    │   └── menu.go
    ├── native
    │   └── native.go
    ├── screens
    │   └── screens.go
    ├── simple
    │   ├── gopher.iconset
    │   │   ├── icon_128x128.png
    │   │   ├── icon_128x128@2x.png
    │   │   ├── icon_16x16.png
    │   │   ├── icon_16x16@2x.png
    │   │   ├── icon_256x256.png
    │   │   ├── icon_256x256@2x.png
    │   │   ├── icon_32x32.png
    │   │   ├── icon_32x32@2x.png
    │   │   └── icon_512x512.png
    │   └── simple.go
    ├── statusbar
    │   ├── bindata.go
    │   ├── icon.png
    │   └── statusbar.go
    └── window
    │   └── window.go
├── globalshortcut.go
├── linkflags.go
├── rect.go
├── redirect.go
├── screen.go
└── vendor
    └── github.com
        └── alexflint
            └── go-arg
                ├── .gitignore
                ├── .travis.yml
                ├── LICENSE
                ├── README.md
                ├── doc.go
                ├── parse.go
                ├── scalar.go
                └── usage.go


/.gitattributes:
--------------------------------------------------------------------------------
1 | *.so filter=lfs diff=lfs merge=lfs -text
2 | *.dylib filter=lfs diff=lfs merge=lfs -text
3 | dist/Gallium.framework/Versions/A/Resources/icudtl.dat filter=lfs diff=lfs merge=lfs -text
4 | dist/Gallium.framework/Versions/A/Resources/content_shell.pak filter=lfs diff=lfs merge=lfs -text
5 | dist/Gallium.framework/Versions/A/Gallium filter=lfs diff=lfs merge=lfs -text
6 | 


--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
 1 | /*.vcxproj*
 2 | /*.xcodeproj/
 3 | /lib/build/
 4 | 
 5 | # Visual Studio
 6 | /*.opensdf
 7 | /*.sdf
 8 | /*.sln
 9 | /*.suo
10 | /ipch/
11 | 
12 | # Linux
13 | out/
14 | 
15 | # Vim
16 | /*.swp
17 | *.app
18 | 
19 | /build/
20 | 


--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
 1 | language: go
 2 | os:
 3 |   - osx
 4 | 
 5 | osx_image: xcode8
 6 | 
 7 | before_install:
 8 |   - brew install git-lfs
 9 |   - git lfs install --system
10 |   - git lfs pull
11 | 
12 | sudo: false
13 | 
14 | go:
15 |   - 1.7
16 |   - tip
17 | 
18 | script:
19 |   - go test -v ./...
20 | 


--------------------------------------------------------------------------------
/Godeps/Godeps.json:
--------------------------------------------------------------------------------
 1 | {
 2 | 	"ImportPath": "github.com/alexflint/gallium",
 3 | 	"GoVersion": "go1.7",
 4 | 	"GodepVersion": "v74",
 5 | 	"Packages": [
 6 | 		"./..."
 7 | 	],
 8 | 	"Deps": [
 9 | 		{
10 | 			"ImportPath": "github.com/alexflint/go-arg",
11 | 			"Rev": "f882700b723834ad1371307b81930cde4b81c0aa"
12 | 		}
13 | 	]
14 | }
15 | 


--------------------------------------------------------------------------------
/Godeps/Readme:
--------------------------------------------------------------------------------
1 | This directory tree is generated automatically by godep.
2 | 
3 | Please do not edit.
4 | 
5 | See https://github.com/tools/godep for more information.
6 | 


--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
 1 | MIT License
 2 | 
 3 | Copyright (c) 2025 Alex Flint
 4 | 
 5 | Permission is hereby granted, free of charge, to any person obtaining a copy
 6 | of this software and associated documentation files (the "Software"), to deal
 7 | in the Software without restriction, including without limitation the rights
 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 | 
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 | 
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 | 


--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
  1 | [![GoDoc](https://godoc.org/github.com/alexflint/gallium?status.svg)](https://godoc.org/github.com/alexflint/gallium)
  2 | [![Build Status](https://travis-ci.org/alexflint/gallium.svg?branch=master)](https://travis-ci.org/alexflint/gallium)
  3 | 
  4 | Write desktop applications in Go, HTML, Javascript, and CSS.
  5 | 
  6 | Gallium is a Go library for managing windows, menus, dock icons, and desktop notifications. Each window contains a webview component, in which you code your UI in HTML. Under the hood, the webview is running Chromium.
  7 | 
  8 | ### Warning
  9 | 
 10 | This is an extremely early version of Gallium. Most APIs will probably change
 11 | before the 1.0 release, and much of the functionality that is already implemented
 12 | remains unstable.
 13 | 
 14 | ### Platforms
 15 | 
 16 | Only OSX is supported right now. I intend to add support for Windows and Linux
 17 | soon.
 18 | 
 19 | ### Discussion
 20 | 
 21 | Join the `#gallium` channel over at the Gophers slack. (You can request an invite to
 22 | the Gophers slack team [here](https://gophersinvite.herokuapp.com/).)
 23 | 
 24 | ### Installation
 25 | 
 26 | Requires go >= 1.7
 27 | 
 28 | First install git large file storage, then install Gallium:
 29 | ```shell
 30 | $ brew install git-lfs
 31 | $ git lfs install
 32 | $ go get github.com/alexflint/gallium  # will not work without git lfs!
 33 | ```
 34 | 
 35 | This will fetch a 92MB framework containing a binary distribution
 36 | of the Chromium content module, so it may take a few moments. This
 37 | is also why git large file storage must be installed (github has
 38 | a limit on file size.)
 39 | 
 40 | ### Quickstart
 41 | 
 42 | ```go
 43 | package main
 44 | 
 45 | import (
 46 |   "os"
 47 |   "runtime"
 48 | 
 49 |   "github.com/alexflint/gallium"
 50 | )
 51 | 
 52 | func main() {
 53 |   runtime.LockOSThread()         // must be the first statement in main - see below
 54 |   gallium.Loop(os.Args, onReady) // must be called from main function
 55 | }
 56 | 
 57 | func onReady(app *gallium.App) {
 58 |   app.OpenWindow("http://example.com/", gallium.FramedWindow)
 59 | }
 60 | ```
 61 | 
 62 | To run the example as a full-fledged UI application, you need to build
 63 | an app bundle:
 64 | ```shell
 65 | $ go build ./example
 66 | $ go install github.com/alexflint/gallium/cmd/gallium-bundle
 67 | $ gallium-bundle example
 68 | $ open example.app
 69 | ```
 70 | 
 71 | ![Result of the example](https://cloud.githubusercontent.com/assets/640247/18623245/c71c2d26-7def-11e6-9ad3-1a5541d7fc86.png)
 72 | 
 73 | If you run the executable directly without building an app bundle then
 74 | many UI elements, such as menus, will not work correctly.
 75 | 
 76 | ```shell
 77 | $ go run example.go
 78 | ```
 79 | 
 80 | ### Menus
 81 | 
 82 | ```go
 83 | func main() {
 84 |   runtime.LockOSThread()
 85 |   gallium.Loop(os.Args, onReady)
 86 | }
 87 | 
 88 | func onReady(app *gallium.App) {
 89 |   app.OpenWindow("http://example.com/", gallium.FramedWindow)
 90 |   app.SetMenu([]gallium.Menu{
 91 |     gallium.Menu{
 92 |       Title: "demo",
 93 |       Entries: []gallium.MenuEntry{
 94 |         gallium.MenuItem{
 95 |           Title:    "About",
 96 |           OnClick:  handleMenuAbout,
 97 |         },
 98 |         gallium.Separator,
 99 |         gallium.MenuItem{
100 |           Title:    "Quit",
101 |           Shortcut: "Cmd+q",
102 |           OnClick:  handleMenuQuit,
103 |         },
104 |       },
105 |     },
106 |   })
107 | }
108 | 
109 | func handleMenuAbout() {
110 |   log.Println("about clicked")
111 |   os.Exit(0)
112 | }
113 | 
114 | func handleMenuQuit() {
115 |   log.Println("quit clicked")
116 |   os.Exit(0)
117 | }
118 | ```
119 | 
120 | ![Menu demo](https://cloud.githubusercontent.com/assets/640247/20243830/17fbaa8e-a91d-11e6-8eca-7ae7c1418a7e.png)
121 | 
122 | ### Status Bar
123 | 
124 | ```go
125 | func main() {
126 |   runtime.LockOSThread()
127 |   gallium.Loop(os.Args, onReady)
128 | }
129 | 
130 | func onReady(app *gallium.App) {
131 |   app.OpenWindow("http://example.com/", gallium.FramedWindow)
132 |   app.AddStatusItem(
133 |     20,
134 |     "statusbar",
135 |     true,
136 |     gallium.MenuItem{
137 |       Title:   "Do something",
138 |       OnClick: handleDoSomething,
139 |     },
140 |     gallium.MenuItem{
141 |       Title:   "Do something else",
142 |       OnClick: handleDoSomethingElse,
143 |     },
144 |   )
145 | }
146 | 
147 | func handleDoSomething() {
148 |   log.Println("do something")
149 | }
150 | 
151 | func handleDoSomethingElse() {
152 |   log.Println("do something else")
153 | }
154 | ```
155 | 
156 | ![Statusbar demo](https://cloud.githubusercontent.com/assets/640247/18698431/06e9d88c-7f7f-11e6-9fa5-d6be40a07840.png)
157 | 
158 | ### Desktop Notifications
159 | 
160 | Note that the OSX Notification Center determines whether or not to show any
161 | given desktop notification, so you may need to open the notification center
162 | and scroll to the bottom in order to see notifications during development.
163 | 
164 | ```go
165 | func main() {
166 |   runtime.LockOSThread()
167 |   gallium.Loop(os.Args, onReady)
168 | }
169 | 
170 | func onReady(app *gallium.App) {
171 |   img, err := gallium.ImageFromPNG(pngBuffer)
172 |   if err != nil {
173 |     ...
174 |   }
175 | 
176 |   app.Post(gallium.Notification{
177 |     Title:    "Wow this is a notification",
178 |     Subtitle: "The subtitle",
179 |     Image:    img,
180 |   })
181 | }
182 | ```
183 | 
184 | ### Dock icons
185 | 
186 | To add a dock icon, create a directory named `myapp.iconset` containing the following files:
187 | ```
188 | icon_16x16.png          # 16 x 16
189 | icon_16x16@2x.png       # 32 x 32
190 | icon_32x32.png          # 32 x 32
191 | icon_32x32@2x.png       # 64 x 64
192 | icon_128x128.png        # 128 x 128
193 | icon_128x128@2x.png     # 256 x 256
194 | icon_256x256.png        # 256 x 256
195 | icon_256x256@2x.png     # 512 x 512
196 | icon_512x512.png        # 512 x 512
197 | icon_512x512@2x.png     # 1024 x 1024
198 | ```
199 | 
200 | Then build you app with
201 | ```shell
202 | gallium-bundle myapp --icon myapp.iconset
203 | ```
204 | 
205 | Alternatively, if you have a `.icns` file:
206 | ```shell
207 | gallium-bundle myapp --icon myapp.icns
208 | ```
209 | 
210 | ### Writing native code
211 | 
212 | You can write C or Objective-C code that interfaces directly with native
213 | windowing APIs. The following example uses the macOS native API `[NSWindow
214 | setAlphaValue]` to create a semi-transparent window.
215 | 
216 | ```go
217 | package main
218 | 
219 | import (
220 |   "log"
221 |   "os"
222 |   "runtime"
223 | 
224 |   "github.com/alexflint/gallium"
225 | )
226 | 
227 | /*
228 | #cgo CFLAGS: -x objective-c
229 | #cgo CFLAGS: -framework Cocoa
230 | #cgo LDFLAGS: -framework Cocoa
231 | 
232 | #include <Cocoa/Cocoa.h>
233 | #include <dispatch/dispatch.h>
234 | 
235 | void SetAlpha(void* window, float alpha) {
236 |   // Cocoa requires that all UI operations happen on the main thread. Since
237 |   // gallium.Loop will have initiated the Cocoa event loop, we can can use
238 |   // dispatch_async to run code on the main thread.
239 |   dispatch_async(dispatch_get_main_queue(), ^{
240 |     NSWindow* w = (NSWindow*)window;
241 |     [w setAlphaValue:alpha];
242 |   });
243 | }
244 | */
245 | import "C"
246 | 
247 | func onReady(ui *gallium.App) {
248 |   window, err := ui.OpenWindow("http://example.com/", gallium.FramedWindow)
249 |   if err != nil {
250 |     log.Fatal(err)
251 |   }
252 |   C.SetAlpha(window.NativeWindow(), 0.5)
253 | }
254 | 
255 | func main() {
256 |   runtime.LockOSThread()
257 |   gallium.Loop(os.Args, onReady)
258 | }
259 | ```
260 | 
261 | ### Relationship to other projects
262 | 
263 | [Electron](http://electron.atom.io/) is a well-known framework for writing desktop applications in node.js. Electron and Gallium are similar in that the core UI is developed in HTML and javascript, but with Gallium the "outer layer" of logic is written in Go. Both Electron and Gallium use Chromium under the hood, and some of the C components for Gallium were ported from Electron.
264 | 
265 | The [Chromium Embedded Framework](https://bitbucket.org/chromiumembedded/cef) is a C framework for embedding Chromium into other applications. I investigated CEF as a basis for Gallium but decided to use [libchromiumcontent](https://github.com/electron/libchromiumcontent) instead.
266 | 
267 | [cef2go](https://github.com/cztomczak/cef2go) is a Go wrapper for Chromium based on CEF, but so far it still requires some manual steps to use as a library.
268 | 
269 | ### Rationale
270 | 
271 | The goal of Gallium is to make it possible to write cross-platform
272 | desktop UI applications in Go.
273 | 
274 | ### Troubleshooting
275 | 
276 | **"file was built for unsupported file format"**
277 | 
278 | If you see the following error:
279 | ```
280 | ld: warning: ignoring file go/src/github.com/alexflint/gallium/dist/Gallium.framework/Gallium, file was built for unsupported file format ( 0x76 0x65 0x72 0x73 0x69 0x6F 0x6E 0x20 0x68 0x74 0x74 0x70 0x73 0x3A 0x2F 0x2F ) which is not the architecture being linked (x86_64): go/src/github.com/alexflint/gallium/dist/Gallium.framework/Gallium
281 | ```
282 | then you probably have an issue with `git lfs`. You can confirm that this is
283 | the problem by checking the size of the file in the error message: it should
284 | be over 1 MB, but if you see a much smaller file then this is your problem.
285 | 
286 | To fix this, try re-installing `git lfs` as described in the installation
287 | section above, then delete and re-install gallium.
288 | 
289 | **No console output**
290 | 
291 | When you run an app bundle with `open Foo.app`, OSX launch services discards
292 | standard output and standard error. If you need to see this output for
293 | debugging purposes, use a redirect:
294 | ```
295 | gallium.RedirectStdoutStderr("output.log")
296 | ```
297 | 
298 | **App does not start**
299 | 
300 | When you run an app bundle with `open Foo.app`, OSX launch services will only
301 | start your app if there is not already another instance of the same
302 | application running, so if your app refuses to start then try checking the
303 | activity monitor for an already running instance.
304 | 
305 | **Menus not visible**
306 | 
307 | If you run the binary directly without building an app
308 | bundle then your menus will not show up, and the window will initially appear
309 | behind other applications.
310 | 
311 | ### UI thread issues and runtime.LockOSThread
312 | 
313 | It is very important that the first statement in your main function
314 | be `runtime.LockOSThread()`. The reason is that gallium calls
315 | out to various C functions in order to create and manage OSX UI elements,
316 | and many of these are required to be called from the first thread
317 | created by the process. But the Go runtime creates many threads and any
318 | one piece of Go code could end up running on any thread. The solution
319 | is `runtime.LockOSThread`, which tells the Go scheduler to lock the
320 | current goroutine so that it will only ever run on the current thread.
321 | Since the main function always starts off on the main thread, this wil
322 | guarantee that the later call to `gallium.Loop` will also be on the main
323 | thread. At this point gallium takes ownership of this thread for its main
324 | event loop and calls the `OnReady` callback in a separate goroutine.
325 | From this point forward it is safe to call gallium functions from any
326 | goroutine.
327 | 
328 | ### Shared libraries and linking issues
329 | 
330 | Gallium is based on Chromium, which it accesses via `Gallium.framework`.
331 | That framework in turn contains `libchromiumcontent.dylib`, which is a 
332 | shared library containing the chromium content module and is distributed
333 | in binary form by the same folks responsible for the excellent Electron
334 | framework. When you build your Go executable, the directives in
335 | `Gallium.framework` instruct the linker to set up the executable to look for
336 | `Gallium.framework` in two places at runtime:
337 |  1. `<dir containing executable>/../Frameworks/Gallium.framework`: this
338 |      will resolve correctly if you choose to build and run your app as a
339 |      bundle (and also means you can distribute the app bundle as a
340 |      self-contained unit).
341 |  2. `$GOPATH/src/github.com/alexflint/dist/Gallium.framework`: this will
342 |      resolve if you choose to run your executable directly.
343 | 
344 | 


--------------------------------------------------------------------------------
/app.go:
--------------------------------------------------------------------------------
  1 | package gallium
  2 | 
  3 | /*
  4 | #cgo CFLAGS: -mmacosx-version-min=10.8
  5 | #cgo CFLAGS: -DGALLIUM_DIR=${SRCDIR}
  6 | #cgo CFLAGS: -Idist/include
  7 | 
  8 | #include <stdlib.h>
  9 | #include "gallium/browser.h"
 10 | #include "gallium/cocoa.h"
 11 | 
 12 | // It does not seem that we can import "_cgo_export.h" from here
 13 | extern void cgo_onReady(int);
 14 | 
 15 | // This is a wrapper around GalliumLoop that adds the function pointer
 16 | // argument, since this does not seem to be possible from Go directly.
 17 | static inline void helper_GalliumLoop(int app_id, const char* arg0, struct gallium_error** err) {
 18 | 	GalliumLoop(app_id, arg0, &cgo_onReady, err);
 19 | }
 20 | */
 21 | import "C"
 22 | import (
 23 | 	"errors"
 24 | 	"fmt"
 25 | 	"log"
 26 | 	"os"
 27 | 	"path/filepath"
 28 | 	"time"
 29 | 	"unsafe"
 30 | )
 31 | 
 32 | var (
 33 | 	errZeroWidth  = errors.New("window width was zero")
 34 | 	errZeroHeight = errors.New("window height was zero")
 35 | )
 36 | 
 37 | // cerr holds a C-allocated error, which must be freed explicitly.
 38 | type cerr struct {
 39 | 	c *C.struct_gallium_error
 40 | }
 41 | 
 42 | // newCerr allocates a new error struct. It must be freed explicitly.
 43 | func newCerr() cerr {
 44 | 	return cerr{
 45 | 		c: (*C.struct_gallium_error)(C.malloc(C.sizeof_struct_gallium_error)),
 46 | 	}
 47 | }
 48 | 
 49 | func (e cerr) free() {
 50 | 	C.free(unsafe.Pointer(e.c))
 51 | }
 52 | 
 53 | func (e *cerr) err() error {
 54 | 	// TODO
 55 | 	return fmt.Errorf("C error")
 56 | }
 57 | 
 58 | // Loop starts the browser loop and does not return unless there is an initialization error
 59 | func Loop(args []string, onReady func(*App)) error {
 60 | 	log.Println("\n\n=== gallium.Loop ===")
 61 | 	cerr := newCerr()
 62 | 	defer cerr.free()
 63 | 
 64 | 	app := App{
 65 | 		ready: make(chan struct{}),
 66 | 	}
 67 | 
 68 | 	go func() {
 69 | 		select {
 70 | 		case <-app.ready:
 71 | 			onReady(&app)
 72 | 		case <-time.After(3 * time.Second):
 73 | 			log.Fatal("Waited for 3 seconds without ready signal")
 74 | 		}
 75 | 	}()
 76 | 
 77 | 	appId := apps.add(&app)
 78 | 	C.helper_GalliumLoop(C.int(appId), C.CString(args[0]), &cerr.c)
 79 | 	return cerr.err()
 80 | }
 81 | 
 82 | // appManager is the singleton for managing app instances
 83 | type appManager []*App
 84 | 
 85 | func (m *appManager) add(app *App) int {
 86 | 	id := len(*m)
 87 | 	*m = append(*m, app)
 88 | 	return id
 89 | }
 90 | 
 91 | func (m *appManager) get(id int) *App {
 92 | 	return (*m)[id]
 93 | }
 94 | 
 95 | var apps appManager
 96 | 
 97 | // App is the handle that allows you to create windows and menus
 98 | type App struct {
 99 | 	// ready is how the cgo onready callback indicates to the Loop goroutine that
100 | 	// chromium is initialized
101 | 	ready chan struct{}
102 | }
103 | 
104 | // WindowOptions contains options for creating windows
105 | type WindowOptions struct {
106 | 	Title            string // String to display in title bar
107 | 	Shape            Rect   // Initial size and position of window
108 | 	TitleBar         bool   // Whether the window title bar
109 | 	Frame            bool   // Whether the window has a frame
110 | 	Resizable        bool   // Whether the window border can be dragged to change its shape
111 | 	CloseButton      bool   // Whether the window has a close button
112 | 	MinButton        bool   // Whether the window has a miniaturize button
113 | 	FullScreenButton bool   // Whether the window has a full screen button
114 | 	Menu             []MenuEntry
115 | }
116 | 
117 | // FramedWindow contains options for an "ordinary" window with title bar,
118 | // frame, and min/max/close buttons.
119 | var FramedWindow = WindowOptions{
120 | 	Shape: Rect{
121 | 		Width:  800,
122 | 		Height: 600,
123 | 		Left:   100,
124 | 		Bottom: 100,
125 | 	},
126 | 	TitleBar:         true,
127 | 	Frame:            true,
128 | 	Resizable:        true,
129 | 	CloseButton:      true,
130 | 	MinButton:        true,
131 | 	FullScreenButton: true,
132 | 	Title:            defaultWindowTitle(),
133 | }
134 | 
135 | func defaultWindowTitle() string {
136 | 	// try the display name first
137 | 	if name := BundleInfo("CFBundleDisplayName"); name != "" {
138 | 		return name
139 | 	}
140 | 	// then fall back to the short name
141 | 	if name := BundleInfo("CFBundleName"); name != "" {
142 | 		return name
143 | 	}
144 | 	// then fall back to the executable name
145 | 	if len(os.Args) > 0 {
146 | 		filepath.Base(os.Args[0])
147 | 	}
148 | 	return ""
149 | }
150 | 
151 | // FramelessWindow contains options for a window with no frame or border, but that
152 | // is still resizable.
153 | var FramelessWindow = WindowOptions{
154 | 	Shape: Rect{
155 | 		Width:  800,
156 | 		Height: 600,
157 | 		Left:   100,
158 | 		Bottom: 100,
159 | 	},
160 | 	Resizable: true,
161 | }
162 | 
163 | // Window represents a window registered with the native UI toolkit (e.g. NSWindow on macOS)
164 | type Window struct {
165 | 	c *C.gallium_window_t
166 | }
167 | 
168 | // OpenWindow creates a window that will load the given URL.
169 | func (app *App) OpenWindow(url string, opt WindowOptions) (*Window, error) {
170 | 	if opt.Shape.Width == 0 {
171 | 		return nil, errZeroWidth
172 | 	}
173 | 	if opt.Shape.Height == 0 {
174 | 		return nil, errZeroHeight
175 | 	}
176 | 	// Create the Cocoa window
177 | 	cwin := C.GalliumOpenWindow(
178 | 		C.CString(url),
179 | 		C.CString(opt.Title),
180 | 		C.int(opt.Shape.Width),
181 | 		C.int(opt.Shape.Height),
182 | 		C.int(opt.Shape.Left),
183 | 		C.int(opt.Shape.Bottom),
184 | 		C.bool(opt.TitleBar),
185 | 		C.bool(opt.Frame),
186 | 		C.bool(opt.Resizable),
187 | 		C.bool(opt.CloseButton),
188 | 		C.bool(opt.MinButton),
189 | 		C.bool(opt.FullScreenButton))
190 | 
191 | 	// TODO: associate menu
192 | 	return &Window{
193 | 		c: cwin,
194 | 	}, nil
195 | }
196 | 
197 | // Shape gets the current shape of the window.
198 | func (w *Window) Shape() Rect {
199 | 	return rectFromC(C.GalliumWindowGetShape(w.c))
200 | }
201 | 
202 | // Shape gets the current shape of the window.
203 | func (w *Window) SetShape(r Rect) {
204 | 	C.GalliumWindowSetShape(w.c, C.int(r.Width), C.int(r.Height), C.int(r.Left), C.int(r.Bottom))
205 | }
206 | 
207 | // URL gets the URL that the window is currently at.
208 | func (w *Window) URL() string {
209 | 	return C.GoString(C.GalliumWindowGetURL(w.c))
210 | }
211 | 
212 | // LoadURL causes the window to load the given URL
213 | func (w *Window) LoadURL(url string) {
214 | 	C.GalliumWindowLoadURL(w.c, C.CString(url))
215 | }
216 | 
217 | // Reload reloads the current URL
218 | func (w *Window) Reload() {
219 | 	C.GalliumWindowReload(w.c)
220 | }
221 | 
222 | // Reload reloads the current URL, ignoring cached versions of resources.
223 | func (w *Window) ReloadNoCache() {
224 | 	C.GalliumWindowReloadNoCache(w.c)
225 | }
226 | 
227 | // Open opens the window. This is the default state for a window created
228 | // via OpenWindow, so you only need to call this if you manually closed
229 | // the window.
230 | func (w *Window) Open() {
231 | 	C.GalliumWindowOpen(w.c)
232 | }
233 | 
234 | // Close closes the window, as if the close button had been clicked.
235 | func (w *Window) Close() {
236 | 	C.GalliumWindowClose(w.c)
237 | }
238 | 
239 | // Miniaturize miniaturizes the window, as if the min button had been clicked.
240 | func (w *Window) Miniaturize() {
241 | 	C.GalliumWindowMiniaturize(w.c)
242 | }
243 | 
244 | // Undo undoes the last text editing action
245 | func (w *Window) Undo() {
246 | 	C.GalliumWindowUndo(w.c)
247 | }
248 | 
249 | // Redo redoes the last text editing action
250 | func (w *Window) Redo() {
251 | 	C.GalliumWindowRedo(w.c)
252 | }
253 | 
254 | // Cut cuts the current text selection to the pastboard
255 | func (w *Window) Cut() {
256 | 	C.GalliumWindowCut(w.c)
257 | }
258 | 
259 | // Copy copies the current text selection to the pasteboard
260 | func (w *Window) Copy() {
261 | 	C.GalliumWindowCopy(w.c)
262 | }
263 | 
264 | // Paste pastes from the pasteboard
265 | func (w *Window) Paste() {
266 | 	C.GalliumWindowPaste(w.c)
267 | }
268 | 
269 | // PasteAndMatchStyle pastes from the pasteboard, matching style to the current element
270 | func (w *Window) PasteAndMatchStyle() {
271 | 	C.GalliumWindowPasteAndMatchStyle(w.c)
272 | }
273 | 
274 | // Delete deletes the current text selection
275 | func (w *Window) Delete() {
276 | 	C.GalliumWindowDelete(w.c)
277 | }
278 | 
279 | // SelectAll selects all text in the current element
280 | func (w *Window) SelectAll() {
281 | 	C.GalliumWindowSelectAll(w.c)
282 | }
283 | 
284 | // Unselect unselects any text selection
285 | func (w *Window) Unselect() {
286 | 	C.GalliumWindowUnselect(w.c)
287 | }
288 | 
289 | // OpenDevTools opens the developer tools for this window.
290 | func (w *Window) OpenDevTools() {
291 | 	C.GalliumWindowOpenDevTools(w.c)
292 | }
293 | 
294 | // CloseDevTools closes the developer tools.
295 | func (w *Window) CloseDevTools() {
296 | 	C.GalliumWindowCloseDevTools(w.c)
297 | }
298 | 
299 | // DevToolsVisible returns whether the developer tools are showing
300 | func (w *Window) DevToolsAreOpen() bool {
301 | 	return bool(C.GalliumWindowDevToolsAreOpen(w.c))
302 | }
303 | 
304 | // NativeWindow gets a operating-system dependent handle for this window. Under macOS
305 | // this is NSWindow*.
306 | func (w *Window) NativeWindow() unsafe.Pointer {
307 | 	return unsafe.Pointer(C.GalliumWindowNativeWindow(w.c))
308 | }
309 | 
310 | // NativeWindow gets an operating-system dependent handle for the window controller.
311 | // Under macOS this is *NSWindowController.
312 | func (w *Window) NativeController() unsafe.Pointer {
313 | 	return unsafe.Pointer(C.GalliumWindowNativeController(w.c))
314 | }
315 | 


--------------------------------------------------------------------------------
/callbacks.go:
--------------------------------------------------------------------------------
 1 | package gallium
 2 | 
 3 | import (
 4 | 	"log"
 5 | 	"unsafe"
 6 | )
 7 | 
 8 | import "C"
 9 | 
10 | // This file contains all Go functions that are exported to cgo. They
11 | // are here because the presence of an export means that the C prelude
12 | // gets copied into two locations.
13 | 
14 | //export cgo_onReady
15 | func cgo_onReady(appId int) {
16 | 	// do not actually call the user function from here because that would
17 | 	// block the UI loop
18 | 	apps.get(appId).ready <- struct{}{}
19 | }
20 | 
21 | //export cgo_onMenuClicked
22 | func cgo_onMenuClicked(data unsafe.Pointer) {
23 | 	if menuMgr == nil {
24 | 		log.Println("onMenuClicked called but menu manager was nil")
25 | 		return
26 | 	}
27 | 
28 | 	if data == nil {
29 | 		log.Println("onMenuClicked called but data parameter was nil")
30 | 		return
31 | 	}
32 | 
33 | 	id := *(*int)(data)
34 | 	item, found := menuMgr.items[id]
35 | 	if !found {
36 | 		log.Printf("onMenuClicked received non-existent ID %d", id)
37 | 		return
38 | 	}
39 | 
40 | 	if item.OnClick == nil {
41 | 		log.Printf("onMenuClicked found %s but OnClick was nil", item.Title)
42 | 		return
43 | 	}
44 | 
45 | 	item.OnClick()
46 | }
47 | 


--------------------------------------------------------------------------------
/cmd/gallium-bundle/bindata.go:
--------------------------------------------------------------------------------
  1 | // Code generated by go-bindata.
  2 | // sources:
  3 | // info.plist.tpl
  4 | // DO NOT EDIT!
  5 | 
  6 | package main
  7 | 
  8 | import (
  9 | 	"bytes"
 10 | 	"compress/gzip"
 11 | 	"fmt"
 12 | 	"io"
 13 | 	"io/ioutil"
 14 | 	"os"
 15 | 	"path/filepath"
 16 | 	"strings"
 17 | 	"time"
 18 | )
 19 | 
 20 | func bindataRead(data []byte, name string) ([]byte, error) {
 21 | 	gz, err := gzip.NewReader(bytes.NewBuffer(data))
 22 | 	if err != nil {
 23 | 		return nil, fmt.Errorf("Read %q: %v", name, err)
 24 | 	}
 25 | 
 26 | 	var buf bytes.Buffer
 27 | 	_, err = io.Copy(&buf, gz)
 28 | 	clErr := gz.Close()
 29 | 
 30 | 	if err != nil {
 31 | 		return nil, fmt.Errorf("Read %q: %v", name, err)
 32 | 	}
 33 | 	if clErr != nil {
 34 | 		return nil, err
 35 | 	}
 36 | 
 37 | 	return buf.Bytes(), nil
 38 | }
 39 | 
 40 | type asset struct {
 41 | 	bytes []byte
 42 | 	info  os.FileInfo
 43 | }
 44 | 
 45 | type bindataFileInfo struct {
 46 | 	name    string
 47 | 	size    int64
 48 | 	mode    os.FileMode
 49 | 	modTime time.Time
 50 | }
 51 | 
 52 | func (fi bindataFileInfo) Name() string {
 53 | 	return fi.name
 54 | }
 55 | func (fi bindataFileInfo) Size() int64 {
 56 | 	return fi.size
 57 | }
 58 | func (fi bindataFileInfo) Mode() os.FileMode {
 59 | 	return fi.mode
 60 | }
 61 | func (fi bindataFileInfo) ModTime() time.Time {
 62 | 	return fi.modTime
 63 | }
 64 | func (fi bindataFileInfo) IsDir() bool {
 65 | 	return false
 66 | }
 67 | func (fi bindataFileInfo) Sys() interface{} {
 68 | 	return nil
 69 | }
 70 | 
 71 | var _infoPlistTpl = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x93\x5f\x6f\x9b\x30\x14\xc5\x9f\xcb\xa7\xf0\x50\x1f\x17\x1b\xba\x56\xdd\x2a\x42\xd5\x40\xd2\x45\xcb\x3f\x0d\x3a\x75\x4f\x93\x67\x5c\x62\xd5\xd8\xc8\x36\xf9\x23\xc4\x77\x9f\x9c\xa4\x69\x9a\x84\x87\xbd\x61\xf9\xfc\x0e\xd7\xf7\x9e\x1b\xdc\xaf\x0a\x0e\x16\x54\x69\x26\x45\xd7\xf5\xa1\xe7\x02\x2a\x88\xcc\x98\xc8\xbb\xee\x53\x3a\xe8\x7c\x75\xef\x43\x27\xf8\x14\x4f\xa3\xf4\xf7\xac\x0f\x4a\xce\xb4\x01\xb3\xa7\xde\x68\x18\x01\xb7\x83\xd0\x43\x59\x72\x8a\x50\x9c\xc6\x60\x36\x1a\x26\x29\xf0\xa1\x87\x50\x7f\xe2\x02\x77\x6e\x4c\x79\x87\xd0\x72\xb9\x84\xd8\xaa\x20\x91\x85\x15\x6a\x34\x53\xb2\xa4\xca\xac\x47\x4c\x9b\x8e\x0f\x3d\x98\x99\xcc\x0d\x9d\x60\xeb\xfe\xa1\x9c\xd0\x09\x32\x46\x4c\xe8\x5c\x04\xaf\x74\x1d\xf6\x2a\xc6\xb3\x31\x26\x73\x26\xe8\x34\xd9\x9c\x02\x64\x2f\x9c\x8b\x40\x1b\xc5\x44\x1e\xfa\xd7\x03\xff\xc6\xfb\x16\xa0\xdd\x79\x47\x46\x83\x5e\x25\x32\x4e\x87\x19\x15\x86\xbd\x30\xaa\x8e\xc1\xba\x86\xc7\x92\xa6\x69\xb3\x99\xe0\x82\xb6\x1a\xd8\xcb\x76\x34\xa9\xca\x52\x2a\x43\xb3\x19\xc7\xe6\x45\xaa\x42\xef\x8d\xb0\x52\xd8\x7e\xec\x2d\xc7\x98\x4c\x93\xe7\x43\x27\xf4\xa6\xd9\x78\xc6\x69\x24\x8b\x92\xf1\xd3\xd7\x10\x59\xbc\xb7\x7d\xa3\xd0\x90\xf3\x45\x01\x09\xc7\x22\x87\xfe\x1f\xef\xb8\xbe\x38\x7d\x2b\xe8\x6c\x5f\x6f\x23\xdf\xf3\xae\xda\xa1\x5f\xdb\xb1\x1d\x63\x8f\xe3\x53\x24\x89\x7f\x9c\x1f\xdd\x4d\x74\xfd\xe5\xac\xfc\x5c\xbb\x0b\x4c\xa4\x5e\xf9\x1e\xf4\xfd\x53\xe6\x99\xc8\xec\x84\xf0\x6e\xaf\xda\xa4\xff\xf1\xe4\x49\xb2\x9b\xa0\x7e\xa8\x8c\x2c\xb0\x61\xe4\x51\xe1\x72\xce\x88\x4e\x96\xcc\xd8\x6c\xe6\x7b\x27\xa3\x2a\x8a\xde\xc9\xef\x2c\x9f\xff\xa4\x5a\xf2\xca\x30\x29\x22\x5c\xe2\xbf\xfc\xa4\xcc\x54\x55\xf4\xe0\xa7\x75\xad\xb0\xc8\x29\xb8\x7c\xa5\xeb\xcf\xe0\x72\x81\x39\xb8\xeb\x02\xd8\x5f\x19\x85\x75\xd3\xd8\xb4\x58\xbe\xae\xad\xc0\xc6\x6e\xeb\x76\x10\x4b\xcb\x7c\xc8\x63\x5d\x53\x91\x35\x8d\x13\xa0\xed\x72\x05\x68\xb3\x7a\xa1\xf3\x2f\x00\x00\xff\xff\xe9\x9e\x25\xe8\x11\x04\x00\x00")
 72 | 
 73 | func infoPlistTplBytes() ([]byte, error) {
 74 | 	return bindataRead(
 75 | 		_infoPlistTpl,
 76 | 		"info.plist.tpl",
 77 | 	)
 78 | }
 79 | 
 80 | func infoPlistTpl() (*asset, error) {
 81 | 	bytes, err := infoPlistTplBytes()
 82 | 	if err != nil {
 83 | 		return nil, err
 84 | 	}
 85 | 
 86 | 	info := bindataFileInfo{name: "info.plist.tpl", size: 1041, mode: os.FileMode(420), modTime: time.Unix(1490294366, 0)}
 87 | 	a := &asset{bytes: bytes, info: info}
 88 | 	return a, nil
 89 | }
 90 | 
 91 | // Asset loads and returns the asset for the given name.
 92 | // It returns an error if the asset could not be found or
 93 | // could not be loaded.
 94 | func Asset(name string) ([]byte, error) {
 95 | 	cannonicalName := strings.Replace(name, "\\", "/", -1)
 96 | 	if f, ok := _bindata[cannonicalName]; ok {
 97 | 		a, err := f()
 98 | 		if err != nil {
 99 | 			return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err)
100 | 		}
101 | 		return a.bytes, nil
102 | 	}
103 | 	return nil, fmt.Errorf("Asset %s not found", name)
104 | }
105 | 
106 | // MustAsset is like Asset but panics when Asset would return an error.
107 | // It simplifies safe initialization of global variables.
108 | func MustAsset(name string) []byte {
109 | 	a, err := Asset(name)
110 | 	if err != nil {
111 | 		panic("asset: Asset(" + name + "): " + err.Error())
112 | 	}
113 | 
114 | 	return a
115 | }
116 | 
117 | // AssetInfo loads and returns the asset info for the given name.
118 | // It returns an error if the asset could not be found or
119 | // could not be loaded.
120 | func AssetInfo(name string) (os.FileInfo, error) {
121 | 	cannonicalName := strings.Replace(name, "\\", "/", -1)
122 | 	if f, ok := _bindata[cannonicalName]; ok {
123 | 		a, err := f()
124 | 		if err != nil {
125 | 			return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err)
126 | 		}
127 | 		return a.info, nil
128 | 	}
129 | 	return nil, fmt.Errorf("AssetInfo %s not found", name)
130 | }
131 | 
132 | // AssetNames returns the names of the assets.
133 | func AssetNames() []string {
134 | 	names := make([]string, 0, len(_bindata))
135 | 	for name := range _bindata {
136 | 		names = append(names, name)
137 | 	}
138 | 	return names
139 | }
140 | 
141 | // _bindata is a table, holding each asset generator, mapped to its name.
142 | var _bindata = map[string]func() (*asset, error){
143 | 	"info.plist.tpl": infoPlistTpl,
144 | }
145 | 
146 | // AssetDir returns the file names below a certain
147 | // directory embedded in the file by go-bindata.
148 | // For example if you run go-bindata on data/... and data contains the
149 | // following hierarchy:
150 | //     data/
151 | //       foo.txt
152 | //       img/
153 | //         a.png
154 | //         b.png
155 | // then AssetDir("data") would return []string{"foo.txt", "img"}
156 | // AssetDir("data/img") would return []string{"a.png", "b.png"}
157 | // AssetDir("foo.txt") and AssetDir("notexist") would return an error
158 | // AssetDir("") will return []string{"data"}.
159 | func AssetDir(name string) ([]string, error) {
160 | 	node := _bintree
161 | 	if len(name) != 0 {
162 | 		cannonicalName := strings.Replace(name, "\\", "/", -1)
163 | 		pathList := strings.Split(cannonicalName, "/")
164 | 		for _, p := range pathList {
165 | 			node = node.Children[p]
166 | 			if node == nil {
167 | 				return nil, fmt.Errorf("Asset %s not found", name)
168 | 			}
169 | 		}
170 | 	}
171 | 	if node.Func != nil {
172 | 		return nil, fmt.Errorf("Asset %s not found", name)
173 | 	}
174 | 	rv := make([]string, 0, len(node.Children))
175 | 	for childName := range node.Children {
176 | 		rv = append(rv, childName)
177 | 	}
178 | 	return rv, nil
179 | }
180 | 
181 | type bintree struct {
182 | 	Func     func() (*asset, error)
183 | 	Children map[string]*bintree
184 | }
185 | var _bintree = &bintree{nil, map[string]*bintree{
186 | 	"info.plist.tpl": &bintree{infoPlistTpl, map[string]*bintree{}},
187 | }}
188 | 
189 | // RestoreAsset restores an asset under the given directory
190 | func RestoreAsset(dir, name string) error {
191 | 	data, err := Asset(name)
192 | 	if err != nil {
193 | 		return err
194 | 	}
195 | 	info, err := AssetInfo(name)
196 | 	if err != nil {
197 | 		return err
198 | 	}
199 | 	err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755))
200 | 	if err != nil {
201 | 		return err
202 | 	}
203 | 	err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
204 | 	if err != nil {
205 | 		return err
206 | 	}
207 | 	err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime())
208 | 	if err != nil {
209 | 		return err
210 | 	}
211 | 	return nil
212 | }
213 | 
214 | // RestoreAssets restores an asset under the given directory recursively
215 | func RestoreAssets(dir, name string) error {
216 | 	children, err := AssetDir(name)
217 | 	// File
218 | 	if err != nil {
219 | 		return RestoreAsset(dir, name)
220 | 	}
221 | 	// Dir
222 | 	for _, child := range children {
223 | 		err = RestoreAssets(dir, filepath.Join(name, child))
224 | 		if err != nil {
225 | 			return err
226 | 		}
227 | 	}
228 | 	return nil
229 | }
230 | 
231 | func _filePath(dir, name string) string {
232 | 	cannonicalName := strings.Replace(name, "\\", "/", -1)
233 | 	return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...)
234 | }
235 | 
236 | 


--------------------------------------------------------------------------------
/cmd/gallium-bundle/bundle.go:
--------------------------------------------------------------------------------
  1 | //go:generate go-bindata -o bindata.go info.plist.tpl
  2 | 
  3 | package main
  4 | 
  5 | import (
  6 | 	"fmt"
  7 | 	"io/ioutil"
  8 | 	"os"
  9 | 	"os/exec"
 10 | 	"path/filepath"
 11 | 	"strings"
 12 | 	"text/template"
 13 | 
 14 | 	arg "github.com/alexflint/go-arg"
 15 | )
 16 | 
 17 | func must(err error, info ...interface{}) {
 18 | 	if err != nil {
 19 | 		fmt.Println(append(info, err.Error())...)
 20 | 		os.Exit(1)
 21 | 	}
 22 | }
 23 | 
 24 | func copyFile(dst, src string) error {
 25 | 	st, err := os.Stat(src)
 26 | 	if err != nil {
 27 | 		return err
 28 | 	}
 29 | 	buf, err := ioutil.ReadFile(src)
 30 | 	if err != nil {
 31 | 		return err
 32 | 	}
 33 | 	return ioutil.WriteFile(dst, buf, st.Mode())
 34 | }
 35 | 
 36 | func copyTree(dst, src string) error {
 37 | 	return filepath.Walk(src, func(path string, info os.FileInfo, err error) error {
 38 | 		// re-stat the path so that we can tell whether it is a symlink
 39 | 		info, err = os.Lstat(path)
 40 | 		if err != nil {
 41 | 			return err
 42 | 		}
 43 | 
 44 | 		rel, err := filepath.Rel(src, path)
 45 | 		if err != nil {
 46 | 			return err
 47 | 		}
 48 | 		targ := filepath.Join(dst, rel)
 49 | 
 50 | 		switch {
 51 | 		case info.IsDir():
 52 | 			return os.Mkdir(targ, 0777)
 53 | 		case info.Mode()&os.ModeSymlink != 0:
 54 | 			referent, err := os.Readlink(path)
 55 | 			if err != nil {
 56 | 				return err
 57 | 			}
 58 | 			return os.Symlink(referent, targ)
 59 | 		default:
 60 | 			return copyFile(targ, path)
 61 | 		}
 62 | 	})
 63 | }
 64 | 
 65 | func main() {
 66 | 	var args struct {
 67 | 		Executable string `arg:"positional,required"`
 68 | 		Output     string `arg:"-o"`
 69 | 		Identifier string `arg:"help:The bundle identifier (CFBundleIdentifier)"`
 70 | 		Name       string `arg:"help:The bundle name (CFBundleName)"`
 71 | 		Icon       string `arg:"help:Path to a .icns file or a .iconset dir"`
 72 | 	}
 73 | 	arg.MustParse(&args)
 74 | 
 75 | 	// If output is empty then use the app name if there is one, or the executable otherwise
 76 | 	if args.Output == "" {
 77 | 		if args.Name == "" {
 78 | 			args.Output = filepath.Base(args.Executable) + ".app"
 79 | 		} else {
 80 | 			args.Output = args.Name + ".app"
 81 | 		}
 82 | 	}
 83 | 
 84 | 	if !strings.HasSuffix(args.Output, ".app") {
 85 | 		fmt.Println("output must end with .app")
 86 | 		os.Exit(1)
 87 | 	}
 88 | 
 89 | 	// If the bundle name is empty then use the app name
 90 | 	if args.Name == "" {
 91 | 		args.Name = strings.TrimSuffix(filepath.Base(args.Output), ".app")
 92 | 	}
 93 | 
 94 | 	// If the bundle identifier is empty then use the bundle name
 95 | 	if args.Identifier == "" {
 96 | 		args.Identifier = args.Name
 97 | 	}
 98 | 
 99 | 	// extras for the Info.plist
100 | 	extraProps := make(map[string]string)
101 | 
102 | 	// get the path to the gallium package
103 | 	golistCmd := exec.Command("go", "list", "-f", "{{.Dir}}", "github.com/alexflint/gallium")
104 | 	golistOut, err := golistCmd.CombinedOutput()
105 | 	if err != nil {
106 | 		fmt.Printf("go list github.com/alexflint/gallium failed:\n%s\n", string(golistOut))
107 | 		os.Exit(1)
108 | 	}
109 | 
110 | 	// Find Gallium.framework
111 | 	galliumDir := strings.TrimSpace(string(golistOut))
112 | 	fwSrc := filepath.Join(galliumDir, "dist", "Gallium.framework")
113 | 	st, err := os.Stat(fwSrc)
114 | 	if err != nil {
115 | 		fmt.Printf("framework not found at %s: %v\n", fwSrc, err)
116 | 		os.Exit(1)
117 | 	}
118 | 	if !st.IsDir() {
119 | 		fmt.Printf("%s is not a directory\n", fwSrc)
120 | 		os.Exit(1)
121 | 	}
122 | 
123 | 	// Create the bundle in a temporary dir
124 | 	tmpBundle, err := ioutil.TempDir("", "")
125 | 	must(err)
126 | 
127 | 	// Create the bundle.app dir
128 | 	must(os.MkdirAll(tmpBundle, 0777))
129 | 
130 | 	// Copy the framework in
131 | 	fwDst := filepath.Join(tmpBundle, "Contents", "Frameworks", "Gallium.framework")
132 | 	must(os.MkdirAll(filepath.Dir(fwDst), 0777))
133 | 	must(copyTree(fwDst, fwSrc))
134 | 
135 | 	// Copy the executable in
136 | 	exeDst := filepath.Join(tmpBundle, "Contents", "MacOS", args.Name)
137 | 	must(os.MkdirAll(filepath.Dir(exeDst), 0777))
138 | 	must(copyFile(exeDst, args.Executable))
139 | 
140 | 	// Copy the icon in
141 | 	if args.Icon != "" {
142 | 		st, err := os.Stat(args.Icon)
143 | 		must(err)
144 | 
145 | 		iconExt := filepath.Ext(args.Icon)
146 | 		iconName := strings.TrimSuffix(filepath.Base(args.Icon), iconExt) + ".icns"
147 | 		iconDst := filepath.Join(tmpBundle, "Contents", "Resources", iconName)
148 | 		must(os.MkdirAll(filepath.Dir(iconDst), 0777))
149 | 		extraProps["CFBundleIconFile"] = iconName
150 | 
151 | 		// There are three kinds of source icons
152 | 		switch {
153 | 		case iconExt == ".icns":
154 | 			if !st.Mode().IsRegular() {
155 | 				fmt.Println("Icon had extension .icns but was not a regular file")
156 | 				os.Exit(1)
157 | 			}
158 | 			must(copyFile(iconDst, args.Icon))
159 | 		case iconExt == ".iconset":
160 | 			if !st.IsDir() {
161 | 				fmt.Println("Icon had extension .icns but was not a directory")
162 | 				os.Exit(1)
163 | 			}
164 | 			must(buildIconSet(iconDst, args.Icon), "error building iconset:")
165 | 		case iconExt == ".png":
166 | 			fmt.Println("Building icons from raw images not implemented yet")
167 | 			os.Exit(1)
168 | 		default:
169 | 			fmt.Println("Unrecognized icon extension:", iconExt)
170 | 			os.Exit(1)
171 | 		}
172 | 	}
173 | 
174 | 	// Write Info.plist
175 | 	tpl, err := template.New("info.plist.tpl").Parse(string(MustAsset("info.plist.tpl")))
176 | 	must(err)
177 | 
178 | 	plistDst := filepath.Join(tmpBundle, "Contents", "Info.plist")
179 | 	w, err := os.Create(plistDst)
180 | 	must(err)
181 | 
182 | 	tpl.Execute(w, map[string]interface{}{
183 | 		"BundleName":       args.Name,
184 | 		"BundleIdentifier": args.Identifier,
185 | 		"Extras":           extraProps,
186 | 	})
187 | 	must(w.Close())
188 | 
189 | 	// Write PkgInfo. I copied this verbatim from another bundle.
190 | 	pkginfo := []byte{0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f}
191 | 	pkginfoDst := filepath.Join(tmpBundle, "Contents", "PkgInfo")
192 | 	must(ioutil.WriteFile(pkginfoDst, pkginfo, 0777))
193 | 
194 | 	// Delete the bundle.app dir if it already exists
195 | 	must(os.RemoveAll(args.Output))
196 | 
197 | 	// Move the temporary dir to the bundle.app location
198 | 	must(os.Rename(tmpBundle, args.Output))
199 | }
200 | 


--------------------------------------------------------------------------------
/cmd/gallium-bundle/iconset.go:
--------------------------------------------------------------------------------
 1 | package main
 2 | 
 3 | import (
 4 | 	"errors"
 5 | 	"os/exec"
 6 | )
 7 | 
 8 | // On macOS, app bundle icons are represents as a .icns file. These files
 9 | // are created using the "iconutil" tool. The input to this tool is a
10 | // ".iconset" directory containing some combination of the files:
11 | //    icon_16x16[@2x].png
12 | //    icon_32x32[@2x].png
13 | //    icon_128x128[@2x].png
14 | //    icon_256x256[@2x].png
15 | //    icon_512x512[@2x].png
16 | 
17 | func buildIconSet(dst, src string) error {
18 | 	cmd := exec.Command("iconutil", "-c", "icns", "-o", dst, src)
19 | 	output, err := cmd.CombinedOutput()
20 | 	if err != nil {
21 | 		return errors.New(string(output))
22 | 	}
23 | 	return nil
24 | }
25 | 


--------------------------------------------------------------------------------
/cmd/gallium-bundle/info.plist.tpl:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="UTF-8"?>
 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 3 | <plist version="1.0">
 4 | <dict>
 5 | 	<key>BuildMachineOSBuild</key>
 6 | 	<string>14F1509</string>
 7 | 	<key>CFBundleIdentifier</key>
 8 | 	<string>{{.BundleIdentifier}}</string>
 9 | 	<key>CFBundleName</key>
10 | 	<string>{{.BundleName}}</string>
11 | 	<key>CFBundleSupportedPlatforms</key>
12 | 	<array>
13 | 		<string>MacOSX</string>
14 | 	</array>
15 | 	<key>DTCompiler</key>
16 | 	<string>com.apple.compilers.llvm.clang.1_0</string>
17 | 	<key>DTPlatformBuild</key>
18 | 	<string>7C1002</string>
19 | 	<key>DTPlatformVersion</key>
20 | 	<string>GM</string>
21 | 	<key>DTSDKBuild</key>
22 | 	<string>15C43</string>
23 | 	<key>DTSDKName</key>
24 | 	<string>macosx10.11</string>
25 | 	<key>DTXcode</key>
26 | 	<string>0721</string>
27 | 	<key>DTXcodeBuild</key>
28 | 	<string>7C1002</string>
29 | 	<key>NSSupportsAutomaticGraphicsSwitching</key>
30 | 	<true/>
31 | 	<key>NSHighResolutionCapable</key>
32 | 	<string>True</string>
33 | 	{{range $key, $val := .Extras}}
34 | 		<key>{{$key}}</key>
35 | 		<string>{{$val}}</string>
36 | 	{{end}}
37 | </dict>
38 | </plist>
39 | 


--------------------------------------------------------------------------------
/cocoa.go:
--------------------------------------------------------------------------------
  1 | package gallium
  2 | 
  3 | /*
  4 | #include <stdlib.h>
  5 | #include "gallium/cocoa.h"
  6 | 
  7 | // It does not seem that we can import "_cgo_export.h" from here
  8 | extern void cgo_onMenuClicked(void*);
  9 | 
 10 | // This is a wrapper around NSMenu_AddMenuItem that adds the function pointer
 11 | // argument, since this does not seem to be possible from Go directly.
 12 | static inline gallium_nsmenuitem_t* helper_NSMenu_AddMenuItem(
 13 | 	gallium_nsmenu_t* menu,
 14 | 	const char* title,
 15 | 	const char* shortcutKey,
 16 | 	gallium_modifier_t shortcutModifier,
 17 | 	void *callbackArg) {
 18 | 
 19 | 	return NSMenu_AddMenuItem(
 20 | 		menu,
 21 | 		title,
 22 | 		shortcutKey,
 23 | 		shortcutModifier,
 24 | 		&cgo_onMenuClicked,
 25 | 		callbackArg);
 26 | }
 27 | */
 28 | import "C"
 29 | import (
 30 | 	"errors"
 31 | 	"fmt"
 32 | 	"log"
 33 | 	"strings"
 34 | 	"unsafe"
 35 | )
 36 | 
 37 | // MenuEntry is the interface for menus and menu items.
 38 | type MenuEntry interface {
 39 | 	menu()
 40 | }
 41 | 
 42 | // Separator displays a horizontal separator within a menu
 43 | var Separator MenuEntry
 44 | 
 45 | // A MenuItem has a title and can be clicked on. It is a leaf node in the menu tree.
 46 | type MenuItem struct {
 47 | 	Title    string
 48 | 	Shortcut KeyCombination
 49 | 	OnClick  func()
 50 | }
 51 | 
 52 | func (MenuItem) menu() {}
 53 | 
 54 | // A Menu has a title and a list of entries. It is a non-leaf node in the menu tree.
 55 | type Menu struct {
 56 | 	Title   string
 57 | 	Entries []MenuEntry
 58 | }
 59 | 
 60 | func (Menu) menu() {}
 61 | 
 62 | // menuMgr is the singleton that owns the menu
 63 | var menuMgr *menuManager
 64 | 
 65 | // menuManager translates Menus and MenuItems to their native equivalent (e.g. NSMenuItem on macOS)
 66 | type menuManager struct {
 67 | 	items map[int]MenuItem
 68 | }
 69 | 
 70 | func newMenuManager() *menuManager {
 71 | 	return &menuManager{make(map[int]MenuItem)}
 72 | }
 73 | 
 74 | func (m *menuManager) add(menu MenuEntry, parent *C.gallium_nsmenu_t) {
 75 | 	switch menu := menu.(type) {
 76 | 	case Menu:
 77 | 		item := C.NSMenu_AddMenuItem(parent, C.CString(menu.Title), nil, 0, nil, nil)
 78 | 		submenu := C.NSMenu_New(C.CString(menu.Title))
 79 | 		C.NSMenuItem_SetSubmenu(item, submenu)
 80 | 		for _, entry := range menu.Entries {
 81 | 			m.add(entry, submenu)
 82 | 		}
 83 | 	case MenuItem:
 84 | 		id := len(m.items)
 85 | 		m.items[id] = menu
 86 | 
 87 | 		callbackArg := C.malloc(C.sizeof_int)
 88 | 		*(*C.int)(callbackArg) = C.int(id)
 89 | 
 90 | 		C.helper_NSMenu_AddMenuItem(
 91 | 			parent,
 92 | 			C.CString(menu.Title),
 93 | 			C.CString(menu.Shortcut.Key),
 94 | 			C.gallium_modifier_t(menu.Shortcut.Modifiers),
 95 | 			callbackArg)
 96 | 	case nil:
 97 | 		// nil means add a separator
 98 | 		C.NSMenu_AddSeparator(parent)
 99 | 	default:
100 | 		log.Printf("unexpected menu entry: %T", menu)
101 | 	}
102 | }
103 | 
104 | func parseShortcut(s string) (key string, modifiers int, err error) {
105 | 	parts := strings.Split(s, "+")
106 | 	if len(parts) == 0 {
107 | 		return "", 0, fmt.Errorf("empty shortcut")
108 | 	}
109 | 	key = parts[len(parts)-1]
110 | 	if len(key) == 0 {
111 | 		return "", 0, fmt.Errorf("empty key")
112 | 	}
113 | 	for _, part := range parts[:len(parts)-1] {
114 | 		switch strings.ToLower(part) {
115 | 		case "cmd":
116 | 			modifiers |= int(C.GalliumCmdModifier)
117 | 		case "ctrl":
118 | 			modifiers |= int(C.GalliumCtrlModifier)
119 | 		case "cmdctrl":
120 | 			modifiers |= int(C.GalliumCmdOrCtrlModifier)
121 | 		case "alt":
122 | 			modifiers |= int(C.GalliumAltOrOptionModifier)
123 | 		case "option":
124 | 			modifiers |= int(C.GalliumAltOrOptionModifier)
125 | 		case "fn":
126 | 			modifiers |= int(C.GalliumFnModifier)
127 | 		case "shift":
128 | 			modifiers |= int(C.GalliumShiftModifier)
129 | 		default:
130 | 			return "", 0, fmt.Errorf("unknown modifier: %s", part)
131 | 		}
132 | 	}
133 | 	return
134 | }
135 | 
136 | func (app *App) SetMenu(menus []Menu) {
137 | 	if menuMgr == nil {
138 | 		menuMgr = newMenuManager()
139 | 	}
140 | 	root := C.NSMenu_New(C.CString("<root>"))
141 | 	for _, m := range menus {
142 | 		menuMgr.add(m, root)
143 | 	}
144 | 	C.NSApplication_SetMainMenu(root)
145 | }
146 | 
147 | type StatusItemOptions struct {
148 | 	Image     *Image      // image to show in the status bar, must be non-nil
149 | 	Width     float64     // width of item in pixels (zero means automatic size)
150 | 	Highlight bool        // whether to highlight the item when clicked
151 | 	Menu      []MenuEntry // the menu to display when the item is clicked
152 | }
153 | 
154 | func (app *App) AddStatusItem(opts StatusItemOptions) {
155 | 	if menuMgr == nil {
156 | 		menuMgr = newMenuManager()
157 | 	}
158 | 	if opts.Image == nil {
159 | 		panic("status item image must not be nil")
160 | 	}
161 | 
162 | 	menu := C.NSMenu_New(C.CString("<statusbar>"))
163 | 	for _, m := range opts.Menu {
164 | 		menuMgr.add(m, menu)
165 | 	}
166 | 	C.NSStatusBar_AddItem(
167 | 		opts.Image.c,
168 | 		C.float(opts.Width),
169 | 		C.bool(opts.Highlight),
170 | 		menu)
171 | }
172 | 
173 | // Image holds a handle to a platform-specific image structure (e.g. NSImage on macOS).
174 | type Image struct {
175 | 	c *C.gallium_nsimage_t
176 | }
177 | 
178 | var (
179 | 	ErrImageDecodeFailed = errors.New("image could not be decoded")
180 | )
181 | 
182 | // ImageFromPNG creates an image from a buffer containing a PNG-encoded image.
183 | func ImageFromPNG(buf []byte) (*Image, error) {
184 | 	cbuf := C.CBytes(buf)
185 | 	defer C.free(cbuf)
186 | 	cimg := C.NSImage_NewFromPNG(cbuf, C.int(len(buf)))
187 | 	if cimg == nil {
188 | 		return nil, ErrImageDecodeFailed
189 | 	}
190 | 	return &Image{cimg}, nil
191 | }
192 | 
193 | // Notification represents a desktop notification
194 | type Notification struct {
195 | 	Title             string
196 | 	Subtitle          string
197 | 	InformativeText   string
198 | 	Image             *Image
199 | 	Identifier        string
200 | 	ActionButtonTitle string
201 | 	OtherButtonTitle  string
202 | }
203 | 
204 | // Post shows the given desktop notification
205 | func (app *App) Post(n Notification) {
206 | 	var cimg *C.gallium_nsimage_t
207 | 	if n.Image != nil {
208 | 		cimg = n.Image.c
209 | 	}
210 | 	cn := C.NSUserNotification_New(
211 | 		C.CString(n.Title),
212 | 		C.CString(n.Subtitle),
213 | 		C.CString(n.InformativeText),
214 | 		cimg,
215 | 		C.CString(n.Identifier),
216 | 		len(n.ActionButtonTitle) > 0,
217 | 		len(n.OtherButtonTitle) > 0,
218 | 		C.CString(n.ActionButtonTitle),
219 | 		C.CString(n.OtherButtonTitle))
220 | 
221 | 	C.NSUserNotificationCenter_DeliverNotification(cn)
222 | }
223 | 
224 | // BundleInfo looks up an entry in the Info.plist for the current bundle.
225 | func BundleInfo(key string) string {
226 | 	cstr := C.MainBundle_ObjectForKey(C.CString(key))
227 | 	if cstr == nil {
228 | 		return ""
229 | 	}
230 | 	defer C.free(unsafe.Pointer(cstr))
231 | 	return C.GoString(cstr)
232 | }
233 | 
234 | // RunApplication is for debugging only. It allows creation of menus and
235 | // desktop notifications without firing up any parts of chromium. It will
236 | // be removed before the 1.0 release.
237 | func RunApplication() {
238 | 	C.NSApplication_Run()
239 | }
240 | 


--------------------------------------------------------------------------------
/dist/Gallium.framework/Frameworks:
--------------------------------------------------------------------------------
1 | Versions/Current/Frameworks


--------------------------------------------------------------------------------
/dist/Gallium.framework/Gallium:
--------------------------------------------------------------------------------
1 | Versions/Current/Gallium


--------------------------------------------------------------------------------
/dist/Gallium.framework/Libraries:
--------------------------------------------------------------------------------
1 | Versions/Current/Libraries


--------------------------------------------------------------------------------
/dist/Gallium.framework/Resources:
--------------------------------------------------------------------------------
1 | Versions/Current/Resources


--------------------------------------------------------------------------------
/dist/Gallium.framework/Versions/A/Gallium:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:f9addc20486e8c137abf9243176ede8abaea034a3964d26498a44902e09d38f9
3 | size 1214020
4 | 


--------------------------------------------------------------------------------
/dist/Gallium.framework/Versions/A/Libraries/ffmpegsumo.so:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:5aa44f3af22436bb46d2979b595e2beb07ba4a73c70c6b6e397cffe303fab3f2
3 | size 2940288
4 | 


--------------------------------------------------------------------------------
/dist/Gallium.framework/Versions/A/Libraries/libchromiumcontent.dylib:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:49647ce56bbd10fa01690182e6f6e7ed800421503e5f1d1ce518cbb4533ffb6a
3 | size 75485320
4 | 


--------------------------------------------------------------------------------
/dist/Gallium.framework/Versions/A/Resources/MainMenu.nib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexflint/gallium/bfa1ecd9241eb3b9f203869fb317c55c3c0c360f/dist/Gallium.framework/Versions/A/Resources/MainMenu.nib


--------------------------------------------------------------------------------
/dist/Gallium.framework/Versions/A/Resources/WindowController.nib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexflint/gallium/bfa1ecd9241eb3b9f203869fb317c55c3c0c360f/dist/Gallium.framework/Versions/A/Resources/WindowController.nib


--------------------------------------------------------------------------------
/dist/Gallium.framework/Versions/A/Resources/content_shell.pak:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:69170143dacce5bf0c05cb0e82afb92c85f7f4eaf4b1073b8d44fdb539260b71
3 | size 7726596
4 | 


--------------------------------------------------------------------------------
/dist/Gallium.framework/Versions/A/Resources/icudtl.dat:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:dcff79b4692b3e54d9a4fa8feda1fe109750636de9720cda370561047e059579
3 | size 10456832
4 | 


--------------------------------------------------------------------------------
/dist/Gallium.framework/Versions/Current:
--------------------------------------------------------------------------------
1 | A


--------------------------------------------------------------------------------
/dist/include/gallium/browser.h:
--------------------------------------------------------------------------------
  1 | #ifndef GALLIUM_BROWSER_H_
  2 | #define GALLIUM_BROWSER_H_
  3 | 
  4 | #include "gallium/core.h"
  5 | 
  6 | #ifdef __cplusplus
  7 | extern "C" {
  8 | #endif
  9 | 
 10 | // gallium_window represents a window
 11 | typedef struct GALLIUM_EXPORT gallium_window gallium_window_t;
 12 | 
 13 | // GalliumLoop runs the chromium browser loop
 14 | GALLIUM_EXPORT int GalliumLoop(
 15 | 	int app_id,
 16 | 	const char* argv0,
 17 | 	void(*on_ready)(int),
 18 | 	struct gallium_error** err);
 19 | 
 20 | // GalliumCreateWindow creates a window pointed at the given url
 21 | GALLIUM_EXPORT gallium_window_t* GalliumOpenWindow(const char* url,
 22 |                                       const char* title,
 23 |                                       int width,
 24 |                                       int height,
 25 |                                       int x,
 26 |                                       int y,
 27 |                                       bool titleBar,
 28 |                                       bool frame,
 29 |                                       bool resizable,
 30 |                                       bool closeButton,
 31 |                                       bool minButton,
 32 |                                       bool fullScreenButton);
 33 | 
 34 |   
 35 | // GalliumWindowGetWidth gets the width of a window
 36 | GALLIUM_EXPORT gallium_rect_t GalliumWindowGetShape(gallium_window_t* window);
 37 | 
 38 | // GalliumWindowGetWidth gets the width of a window
 39 | GALLIUM_EXPORT void GalliumWindowSetShape(gallium_window_t* window,
 40 |                                           int width,
 41 |                                           int height,
 42 |                                           int left,
 43 |                                           int top);
 44 | 
 45 | // GalliumWindowGetURL gets the URL that the window is currently at
 46 | GALLIUM_EXPORT const char* GalliumWindowGetURL(gallium_window_t* window);
 47 | 
 48 | // GalliumWindowLoadURL causes the window to load the given URL
 49 | GALLIUM_EXPORT void GalliumWindowLoadURL(gallium_window_t* window, const char* url);
 50 | 
 51 | // GalliumWindowReload reloads the current page
 52 | GALLIUM_EXPORT void GalliumWindowReload(gallium_window_t* window);
 53 | 
 54 | // GalliumWindowReload reloads the current page, ignoring any cached resources
 55 | GALLIUM_EXPORT void GalliumWindowReloadNoCache(gallium_window_t* window);
 56 | 
 57 | // GalliumWindowOpen opens the window (only for use after GalliumWindowClose)
 58 | GALLIUM_EXPORT void GalliumWindowOpen(gallium_window_t* window);
 59 | 
 60 | // GalliumWindowClose closes the window
 61 | GALLIUM_EXPORT void GalliumWindowClose(gallium_window_t* window);
 62 | 
 63 | // GalliumWindowClose miniaturizes the window
 64 | GALLIUM_EXPORT void GalliumWindowMiniaturize(gallium_window_t* window);
 65 | 
 66 | // GalliumWindowUndo undoes the last text editing action
 67 | GALLIUM_EXPORT void GalliumWindowUndo(gallium_window_t* window);
 68 | 
 69 | // GalliumWindowRedo redoes the last text editing action
 70 | GALLIUM_EXPORT void GalliumWindowRedo(gallium_window_t* window);
 71 | 
 72 | // GalliumWindow cuts the current text selection to the pastboard
 73 | GALLIUM_EXPORT void GalliumWindowCut(gallium_window_t* window);
 74 | 
 75 | // GalliumWindow copies the current text selection to the pasteboard
 76 | GALLIUM_EXPORT void GalliumWindowCopy(gallium_window_t* window);
 77 | 
 78 | // GalliumWindow pastes from the pasteboard
 79 | GALLIUM_EXPORT void GalliumWindowPaste(gallium_window_t* window);
 80 | 
 81 | // GalliumWindow pastes from the pasteboard, matching style to the current element
 82 | GALLIUM_EXPORT void GalliumWindowPasteAndMatchStyle(gallium_window_t* window);
 83 | 
 84 | // GalliumWindow deletes the current text selection
 85 | GALLIUM_EXPORT void GalliumWindowDelete(gallium_window_t* window);
 86 | 
 87 | // GalliumWindow selects all text in the current element
 88 | GALLIUM_EXPORT void GalliumWindowSelectAll(gallium_window_t* window);
 89 | 
 90 | // GalliumWindowUnselect unselects any text selection
 91 | GALLIUM_EXPORT void GalliumWindowUnselect(gallium_window_t* window);
 92 | 
 93 | // GalliumWindowOpenDevTools opens the developer tools for the given window
 94 | GALLIUM_EXPORT void GalliumWindowOpenDevTools(gallium_window_t* window);
 95 | 
 96 | // GalliumWindowCloseDevTools closes the developer tools for the given window
 97 | GALLIUM_EXPORT void GalliumWindowCloseDevTools(gallium_window_t* window);
 98 |   
 99 | // GalliumWindowDevToolsVisible returns true if the developer tools are currently visible for the given window
100 | GALLIUM_EXPORT bool GalliumWindowDevToolsAreOpen(gallium_window_t* window);
101 |   
102 | // GalliumWindowNativeWindow gets a native handle for this window (NSWindow*).
103 | GALLIUM_EXPORT void* GalliumWindowNativeWindow(gallium_window_t* window);
104 | 
105 | // GalliumWindowNativeWindow gets a native handle for the window controller (NSWindowController*).
106 | GALLIUM_EXPORT void* GalliumWindowNativeController(gallium_window_t* window);
107 | 
108 | // GalliumWindowNativeWindow gets a native handle for the window content (content::WebContent*).
109 | GALLIUM_EXPORT void* GalliumWindowNativeContent(gallium_window_t* window);
110 |   
111 | #ifdef __cplusplus
112 | }
113 | #endif
114 | 
115 | #endif // ifndef GALLIUM_BROWSER_H_
116 | 


--------------------------------------------------------------------------------
/dist/include/gallium/cocoa.h:
--------------------------------------------------------------------------------
 1 | #ifndef GALLIUM_COCOA_H_
 2 | #define GALLIUM_COCOA_H_
 3 | 
 4 | #include "gallium/core.h"
 5 | #include "gallium/browser.h"
 6 | 
 7 | #ifdef __cplusplus
 8 | extern "C" {
 9 | #endif
10 | 
11 | typedef void(*gallium_callback_t)(void*);
12 | 
13 | typedef struct GALLIUM_EXPORT gallium_nsmenu gallium_nsmenu_t;
14 | typedef struct GALLIUM_EXPORT gallium_nsmenuitem gallium_nsmenuitem_t;
15 | typedef struct GALLIUM_EXPORT gallium_nsusernotification gallium_nsusernotification_t;
16 | typedef struct GALLIUM_EXPORT gallium_nsimage gallium_nsimage_t;
17 | 
18 | GALLIUM_EXPORT gallium_nsmenu_t* NSMenu_New(const char* title);
19 | 
20 | GALLIUM_EXPORT gallium_nsmenuitem_t* NSMenu_AddMenuItem(
21 | 	gallium_nsmenu_t* menu,
22 | 	const char* title,
23 | 	const char* shortcutkey,
24 | 	const gallium_modifier_t shortcutModifier,
25 | 	gallium_callback_t callback,
26 | 	void* callbackArg);
27 | 
28 | GALLIUM_EXPORT void NSMenu_AddSeparator(
29 | 	gallium_nsmenu_t* menu);
30 | 
31 | GALLIUM_EXPORT void NSMenuItem_SetSubmenu(
32 | 	gallium_nsmenuitem_t* menuitem,
33 | 	gallium_nsmenu_t* submenu);
34 | 
35 | GALLIUM_EXPORT void NSStatusBar_AddItem(
36 | 	gallium_nsimage_t* image,
37 | 	float width,
38 | 	bool highlightMode,
39 | 	gallium_nsmenu_t* menu);
40 | 
41 |   
42 | GALLIUM_EXPORT gallium_nsusernotification_t* NSUserNotification_New(
43 | 	const char* title,
44 | 	const char* subtitle,
45 | 	const char* informativeText,
46 | 	gallium_nsimage_t* contentImage,
47 | 	const char* identifier,
48 | 	bool hasActionButton,
49 | 	bool hasReplyButton,
50 | 	const char* actionButtonTitle,
51 | 	const char* otherButtonTitle);
52 | 
53 | GALLIUM_EXPORT void NSUserNotificationCenter_DeliverNotification(
54 | 	gallium_nsusernotification_t* n);
55 | 
56 | GALLIUM_EXPORT gallium_nsimage_t* NSImage_NewFromPNG(
57 | 	const void* buf,
58 | 	int size);
59 | 
60 | GALLIUM_EXPORT void NSImage_WriteToFile(gallium_nsimage_t* img, const char* path);
61 | 
62 | GALLIUM_EXPORT void NSApplication_SetMainMenu(
63 | 	gallium_nsmenu_t* submenu);
64 | 
65 | GALLIUM_EXPORT void NSApplication_Run();
66 | 
67 | GALLIUM_EXPORT char* MainBundle_ObjectForKey(const char* key);
68 | 
69 | #ifdef __cplusplus
70 | }
71 | #endif
72 | 
73 | #endif // ifndef GALLIUM_COCOA_H_
74 | 


--------------------------------------------------------------------------------
/dist/include/gallium/core.h:
--------------------------------------------------------------------------------
 1 | #ifndef GALLIUM_EXPORT_H_
 2 | #define GALLIUM_EXPORT_H_
 3 | 
 4 | #include <stdbool.h>
 5 | #include <stdint.h>
 6 | 
 7 | #ifdef __cplusplus
 8 | extern "C" {
 9 | #endif
10 | 
11 | // GALLIUM_EXPORT is the macro for exporting symbols
12 | #define GALLIUM_EXPORT __attribute__ ((visibility ("default")))
13 | 
14 | // gallium_error represents an error
15 | typedef struct GALLIUM_EXPORT gallium_error {
16 | 	const char* msg;
17 | } gallium_error_t;
18 | 
19 | // gallium_modifier represents a modifier mask for a keyboard shortcut
20 | typedef enum GALLIUM_EXPORT gallium_modifier {
21 | 	GalliumCmdModifier = 1 << 0,
22 | 	GalliumCtrlModifier = 1 << 1,
23 | 	GalliumCmdOrCtrlModifier = 1 << 2,
24 | 	GalliumAltOrOptionModifier = 1 << 3,
25 | 	GalliumFnModifier = 1 << 4,
26 | 	GalliumShiftModifier = 1 << 5,
27 | } gallium_modifier_t;
28 | 
29 | // gallium_rect represents a rectangle
30 | typedef struct GALLIUM_EXPORT {
31 | 	int width;
32 | 	int height;
33 | 	int left;
34 | 	int bottom;
35 | } gallium_rect_t;
36 | 
37 | #ifdef __cplusplus
38 | }
39 | #endif
40 | 
41 | #endif // ifndef GALLIUM_EXPORT_H_
42 | 
43 | 


--------------------------------------------------------------------------------
/dist/include/gallium/globalshortcut.h:
--------------------------------------------------------------------------------
 1 | #ifndef GALLIUM_GLOBALSHORTCUT_H_
 2 | #define GALLIUM_GLOBALSHORTCUT_H_
 3 | 
 4 | #include "gallium/core.h"
 5 | 
 6 | #ifdef __cplusplus
 7 | extern "C" {
 8 | #endif
 9 | 
10 | typedef void(*global_shortcut_handler_t)(int64_t);
11 | 
12 | void GALLIUM_EXPORT GalliumAddGlobalShortcut(int ID,
13 |                                              const char* key,
14 |                                              gallium_modifier_t mask,
15 |                                              global_shortcut_handler_t handler);
16 | 
17 | #ifdef __cplusplus
18 | }
19 | #endif
20 | 
21 | #endif // ifndef GALLIUM_GLOBALSHORTCUT_H_
22 | 
23 | 


--------------------------------------------------------------------------------
/dist/include/gallium/screen.h:
--------------------------------------------------------------------------------
 1 | #ifndef GALLIUM_SCREEN_H_
 2 | #define GALLIUM_SCREEN_H_
 3 | 
 4 | #include "gallium/core.h"
 5 | 
 6 | #ifdef __cplusplus
 7 | extern "C" {
 8 | #endif
 9 | 
10 | typedef struct GALLIUM_EXPORT gallium_screen gallium_screen_t;
11 | 
12 | // GalliumScreenCount gets the number of screens
13 | GALLIUM_EXPORT int GalliumScreenCount();
14 | 
15 | // GalliumScreen gets the i-th screen
16 | GALLIUM_EXPORT gallium_screen_t* GalliumScreen(int index);
17 | 
18 | // GalliumFocusedScreen gets the screen containing the currently focused window.
19 | GALLIUM_EXPORT gallium_screen_t* GalliumFocusedScreen();
20 | 
21 | // GalliumScreenShape gets the shape of a screen
22 | GALLIUM_EXPORT gallium_rect_t GalliumScreenShape(gallium_screen_t*);
23 | 
24 | // GalliumScreenShape gets the usable area of a screen (excludes dock and menubar)
25 | GALLIUM_EXPORT gallium_rect_t GalliumScreenUsable(gallium_screen_t*);
26 | 
27 | // GalliumScreenBitsPerPixel gets the bits per pixels for a screen
28 | GALLIUM_EXPORT int GalliumScreenBitsPerPixel(gallium_screen_t*);
29 | 
30 | // GalliumScreenID gets the unique ID for a screen
31 | GALLIUM_EXPORT int GalliumScreenID(gallium_screen_t*);
32 | 
33 | #ifdef __cplusplus
34 | }
35 | #endif
36 | 
37 | #endif // ifndef GALLIUM_SCREEN_H_
38 | 


--------------------------------------------------------------------------------
/examples/controller/controller.go:
--------------------------------------------------------------------------------
  1 | package main
  2 | 
  3 | import (
  4 | 	"fmt"
  5 | 	"log"
  6 | 	"net/http"
  7 | 	"os"
  8 | 	"runtime"
  9 | 
 10 | 	"github.com/alexflint/gallium"
 11 | )
 12 | 
 13 | var html = `
 14 | <!doctype html>
 15 | <html><head></head><body>
 16 | <div><a href="/resize">Resize</a></div>
 17 | <div><a href="/reload">Reload</a></div>
 18 | <div><a href="/reloadnocache">Reload, ignoring cache</a></div>
 19 | <div><a href="/close">Close</a></div>
 20 | <div><a href="/miniaturize">Miniaturize</a></div>
 21 | <div><a href="/window">New window</a></div>
 22 | <div><a href="/load">Load example.com</a></div>
 23 | <div><a href="/opendev">Open Dev Tools</a></div>
 24 | <div><a href="/closedev">Close Dev Tools</a></div>
 25 | </body></html>
 26 | `
 27 | 
 28 | type app struct {
 29 | 	ui     *gallium.App
 30 | 	window *gallium.Window
 31 | }
 32 | 
 33 | func (a *app) handleIndex(w http.ResponseWriter, r *http.Request) {
 34 | 	fmt.Fprint(w, html)
 35 | }
 36 | 
 37 | func (a *app) handleResize(w http.ResponseWriter, r *http.Request) {
 38 | 	shape := a.window.Shape()
 39 | 	shape.Width += 100
 40 | 	shape.Height += 100
 41 | 	a.window.SetShape(shape)
 42 | 	http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
 43 | }
 44 | 
 45 | func (a *app) handleReload(w http.ResponseWriter, r *http.Request) {
 46 | 	a.window.Reload()
 47 | }
 48 | 
 49 | func (a *app) handleReloadNoCache(w http.ResponseWriter, r *http.Request) {
 50 | 	a.window.ReloadNoCache()
 51 | }
 52 | 
 53 | func (a *app) handleClose(w http.ResponseWriter, r *http.Request) {
 54 | 	a.window.Close()
 55 | }
 56 | 
 57 | func (a *app) handleMiniaturize(w http.ResponseWriter, r *http.Request) {
 58 | 	a.window.Miniaturize()
 59 | }
 60 | 
 61 | func (a *app) handleWindow(w http.ResponseWriter, r *http.Request) {
 62 | 	a.ui.OpenWindow("http://www.example.com/", gallium.FramedWindow)
 63 | 	http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
 64 | }
 65 | 
 66 | func (a *app) handleLoad(w http.ResponseWriter, r *http.Request) {
 67 | 	a.window.LoadURL("http://www.example.com/")
 68 | }
 69 | 
 70 | func (a *app) handleOpenDev(w http.ResponseWriter, r *http.Request) {
 71 | 	a.window.OpenDevTools()
 72 | 	http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
 73 | }
 74 | 
 75 | func (a *app) handleCloseDev(w http.ResponseWriter, r *http.Request) {
 76 | 	a.window.CloseDevTools()
 77 | 	http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
 78 | }
 79 | 
 80 | func onReady(ui *gallium.App) {
 81 | 	opts := gallium.FramedWindow
 82 | 	opts.Shape.Width = 300
 83 | 	opts.Shape.Height = 200
 84 | 	window, err := ui.OpenWindow("http://127.0.0.1:9478/", opts)
 85 | 	if err != nil {
 86 | 		log.Fatal(err)
 87 | 	}
 88 | 
 89 | 	app := app{
 90 | 		ui:     ui,
 91 | 		window: window,
 92 | 	}
 93 | 	http.HandleFunc("/", app.handleIndex)
 94 | 	http.HandleFunc("/resize", app.handleResize)
 95 | 	http.HandleFunc("/reload", app.handleReload)
 96 | 	http.HandleFunc("/reloadnocache", app.handleReloadNoCache)
 97 | 	http.HandleFunc("/close", app.handleClose)
 98 | 	http.HandleFunc("/miniaturize", app.handleMiniaturize)
 99 | 	http.HandleFunc("/window", app.handleWindow)
100 | 	http.HandleFunc("/load", app.handleLoad)
101 | 	http.HandleFunc("/opendev", app.handleOpenDev)
102 | 	http.HandleFunc("/closedev", app.handleCloseDev)
103 | 	go http.ListenAndServe(":9478", nil)
104 | }
105 | 
106 | func main() {
107 | 	runtime.LockOSThread()
108 | 	gallium.RedirectStdoutStderr(os.ExpandEnv("$HOME/Library/Logs/Gallium.log"))
109 | 	gallium.Loop(os.Args, onReady)
110 | }
111 | 


--------------------------------------------------------------------------------
/examples/desktop-notification/bindata.go:
--------------------------------------------------------------------------------
  1 | // Code generated by go-bindata.
  2 | // sources:
  3 | // gopher.png
  4 | // DO NOT EDIT!
  5 | 
  6 | package main
  7 | 
  8 | import (
  9 | 	"bytes"
 10 | 	"compress/gzip"
 11 | 	"fmt"
 12 | 	"io"
 13 | 	"io/ioutil"
 14 | 	"os"
 15 | 	"path/filepath"
 16 | 	"strings"
 17 | 	"time"
 18 | )
 19 | 
 20 | func bindataRead(data []byte, name string) ([]byte, error) {
 21 | 	gz, err := gzip.NewReader(bytes.NewBuffer(data))
 22 | 	if err != nil {
 23 | 		return nil, fmt.Errorf("Read %q: %v", name, err)
 24 | 	}
 25 | 
 26 | 	var buf bytes.Buffer
 27 | 	_, err = io.Copy(&buf, gz)
 28 | 	clErr := gz.Close()
 29 | 
 30 | 	if err != nil {
 31 | 		return nil, fmt.Errorf("Read %q: %v", name, err)
 32 | 	}
 33 | 	if clErr != nil {
 34 | 		return nil, err
 35 | 	}
 36 | 
 37 | 	return buf.Bytes(), nil
 38 | }
 39 | 
 40 | type asset struct {
 41 | 	bytes []byte
 42 | 	info  os.FileInfo
 43 | }
 44 | 
 45 | type bindataFileInfo struct {
 46 | 	name    string
 47 | 	size    int64
 48 | 	mode    os.FileMode
 49 | 	modTime time.Time
 50 | }
 51 | 
 52 | func (fi bindataFileInfo) Name() string {
 53 | 	return fi.name
 54 | }
 55 | func (fi bindataFileInfo) Size() int64 {
 56 | 	return fi.size
 57 | }
 58 | func (fi bindataFileInfo) Mode() os.FileMode {
 59 | 	return fi.mode
 60 | }
 61 | func (fi bindataFileInfo) ModTime() time.Time {
 62 | 	return fi.modTime
 63 | }
 64 | func (fi bindataFileInfo) IsDir() bool {
 65 | 	return false
 66 | }
 67 | func (fi bindataFileInfo) Sys() interface{} {
 68 | 	return nil
 69 | }
 70 | 
 71 | var _gopherPng = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x8c\xb8\x73\x8c\x27\xc0\xbf\x68\xf9\x6d\x7f\xdb\xb6\xad\x69\xbb\xa7\x6d\xdb\x9c\xb6\x6d\xdb\xb6\x6d\xdb\x3d\xad\x69\xdb\xb6\x6d\x73\x73\xdf\xdd\xdc\xcd\xdb\xf7\xdb\x64\x53\xa9\x54\x52\x75\x4e\x52\xf9\xfc\x79\x22\x14\xe4\xc4\xe1\x61\x70\x60\x00\x00\x00\xbc\xa4\x84\x88\x12\x00\x00\x30\x06\x00\x00\xca\x40\x00\x00\x00\x90\x79\xfe\xca\x01\x00\x40\x8f\x2d\x84\x85\x15\x2c\x8c\x8c\x00\x00\xaa\x04\xa3\x3f\x7f\x72\x77\x4f\xf7\x0f\xc7\xc9\xfa\xfa\x14\x14\x54\x94\x0e\x09\x0e\xb1\xb0\x91\xb1\x4b\xfa\x7c\x73\x03\x62\x02\x32\x40\xe0\x50\x92\xa2\x60\xf1\xc0\x40\xbd\x05\x2e\xbb\x3f\xbb\x55\x20\x55\xfa\x46\xfb\x6e\xaf\x70\xc2\x8d\xff\xb4\x57\xc3\x32\x47\x05\xb0\xf6\x65\xc2\x35\x63\x49\x10\x02\x0c\x8b\x92\x17\xf7\x8d\x89\xbe\x20\xc2\x17\x26\xa4\x61\xfc\xf7\xa3\x99\x04\x5a\x25\x94\xd8\xd3\x75\x01\x86\x66\x61\xe0\x5c\x60\x6b\x74\x70\x70\x32\x3c\xe4\x15\xe8\x44\x7f\xe1\xa6\xdf\x20\x52\x44\x33\xce\xb0\xc9\x61\x42\x53\x53\x53\x61\x62\xa9\xdf\x24\x2b\x60\xfa\x53\x86\xc8\x2b\x3a\x86\x60\x72\x3d\xc6\xde\x44\x21\xde\x44\x23\xc8\x2b\xa8\x05\x5a\x14\x7e\x0b\xf8\xaf\x90\xf7\x8a\xf4\xf3\x32\xb1\xc8\xf7\x8f\x0a\xa4\x88\xb8\xa1\x82\xe7\xdb\x07\xd7\x23\xed\x05\x21\x09\xfb\x1f\xce\x17\x32\x03\x61\xab\x25\xfc\x05\x03\xfa\xfd\xfb\x03\x88\xfd\x89\x13\x0a\x72\x0d\x40\xfe\x29\x86\x72\x44\xef\x47\xd3\x47\x97\x44\xd3\x62\xdd\x30\x45\x30\x41\x30\xc9\xfe\xe9\xec\xfb\x35\x89\x37\xd6\x1d\xff\x06\x1f\x45\x2e\x0d\x35\x41\xa7\xc6\xbb\xac\xb6\xec\x65\x9d\x6a\xbd\xb0\xda\xd3\x10\xd6\x74\x73\xac\xb0\x7f\xba\xff\x3a\x90\x31\xea\x11\x30\x91\x60\x05\xdb\x46\xf1\x02\x4a\x40\x9d\x5b\xd1\x2d\xd4\x9d\xf4\x1a\xfc\x56\x7a\x37\x71\xcb\x80\x31\x8b\xbc\x4a\x7c\x4a\xe3\x2e\x4a\xa5\x7a\x1a\x66\x5f\x17\x1e\x39\xaa\x37\x67\x3f\xc7\x60\x98\x34\x18\x33\x58\x27\xa1\x22\x31\x2e\x49\x90\x34\x9e\x96\x9a\xca\x47\xac\x4c\x51\x45\xef\x25\x5d\x2b\xbf\x2d\xfa\x1d\x37\xa0\x36\x24\x44\xce\x5b\xd2\x36\x6e\xa5\x0a\xa3\x22\xab\xe2\x57\x89\xaf\x72\x33\x0f\x5c\x52\x99\xff\xcc\x77\x11\xf0\x4a\x94\xab\xac\x4d\xc9\xcd\xdf\xa6\xfd\x22\x85\x84\x85\xb3\x8a\x31\x8c\xb6\x91\x3d\x94\xcd\x90\xd5\xcf\xd4\x65\xdc\xb1\x68\x18\x74\x0c\x54\xcd\x71\xa9\x95\xcd\xb6\xc9\xcf\xa9\xfa\xdb\x12\xd4\x50\x14\x9b\x94\xd9\x94\x18\x15\x58\xd5\x9d\x15\xd8\xd5\x18\xd6\x59\x56\x9b\x16\xd1\x16\x13\xd7\x65\x57\xaf\x1f\xe8\xe7\x2b\xe0\xb3\x3b\x98\x5f\xd2\xdf\x25\x44\x1f\xda\x03\x67\x16\x19\x1f\xd5\x1c\x19\x19\x5e\x1b\x9e\x81\xdd\x45\x79\x2d\x08\xaa\x5d\x68\xab\xa4\xe1\x28\x3c\x9e\xb9\x98\x75\x86\x87\x8d\x91\x91\xa1\xe9\xd4\xc4\x70\xdc\x78\xb2\x76\xa2\x8e\x66\x4d\xe3\xad\x5e\xad\x9b\xa8\xda\x59\x79\x29\x1b\xe2\x6b\x22\xb9\x54\x8b\x33\xac\x55\xd7\x59\xf1\x84\x88\xfb\x94\x69\x99\x39\xd3\x3a\xde\x82\xde\x4a\x78\x95\x7c\x4d\x73\xce\xb7\x55\xb5\xbe\xb2\xea\xe7\x56\x38\x55\xbc\x96\xf4\x23\x17\x93\xe7\xea\x1e\x3a\x3c\xf9\xad\xb9\x73\x42\x36\xc9\xcb\xbb\xe3\xdd\x3f\x2f\x4a\x12\xa5\x9d\xe6\xad\x9d\xda\xf1\xb9\x3d\x1e\xaf\x5a\xb6\xd2\x5e\xbd\xd5\xb6\xed\xf8\xaf\x55\x96\x22\xab\xcd\x9a\x6d\xad\xd5\x27\x6c\x69\xfa\xab\x4b\xf7\x25\x7b\x0b\xb3\xf5\xa7\xbf\x3f\x5b\x98\x3f\xae\x99\x10\x95\xbf\x67\xbf\xf8\xa9\xc2\xc9\x2c\x71\xe6\x9b\x9b\xff\xac\xf0\xb9\xa4\x48\x1d\xa5\xee\xbb\x8b\xef\xa4\x74\xaa\xa6\xcb\xed\xfc\x86\x7a\x87\xff\x8e\xf1\xa6\x61\x35\xe9\x6b\x86\x59\x3f\xbc\x9b\xe7\x95\xfb\xa7\xe6\xb3\x0b\x96\x30\x93\x2f\xc3\xd7\xf7\xc9\xa5\xff\xe5\x36\x0f\xb4\x57\xee\xcb\xe2\xeb\xe4\xf5\x87\x1f\x00\x0f\x40\x64\xf5\x2b\x1f\x8a\x01\x00\x00\xa0\x86\xd2\xe2\x22\x80\x9f\xb0\xb8\xc9\x5e\x00\x00\x00\x6d\x2f\xa1\xe9\x04\x00\xe8\x88\xfd\xd7\x06\x41\x4b\x16\x16\x04\x00\x00\x50\xce\x92\xb2\xa2\x50\xbb\xd0\xd8\xf0\x58\xa8\x8f\x97\x01\x89\x00\x00\x66\xa3\xa7\x8a\x86\xb3\x92\x81\x1b\x91\xbd\xa3\x9d\xa9\x85\xb5\x09\x91\xb3\x87\xbd\x09\x11\xa7\xa1\x85\x0d\x00\x60\x1e\x50\x92\x25\xe9\x4a\xca\xe5\x16\x72\xa2\x11\x92\xe6\xdf\xa3\x89\xb0\xee\xc4\x73\xfb\x5d\xf6\x4d\x2f\x11\x99\x9c\xac\xea\x97\x92\x53\x29\x93\x10\x0d\x04\xbf\xcd\xdc\x20\xd2\x28\x8d\xfd\xf9\x26\x7c\xd0\xff\x1c\xa3\x36\x41\xb5\x7c\x6c\x18\x32\x29\x92\x7f\xbe\x88\x6b\xfa\x39\x9b\xf9\xe8\x9c\x7d\xda\xe6\xe1\x23\x38\x1a\x01\xe4\x91\x3a\xd4\xbf\x6e\xde\xd3\x33\xe5\x26\x4a\x1d\xf2\xfe\xf0\xc5\xf1\xf9\xb1\x28\x34\x92\x27\xa7\x0b\x3d\xbf\xdd\xb2\xec\x04\x0d\x7a\x39\xc8\x7d\x5e\x26\xde\xbf\xbf\xbd\xad\x7c\xc4\x97\xed\xe9\xd5\xa1\x4e\x7f\x4c\xc3\x6d\x48\xf9\xc0\xa3\xbc\x25\xaf\xd4\xe1\x7e\x19\x94\x72\x31\x29\x6c\xae\x1d\x89\xf6\x19\xca\x54\x94\x9e\xa8\xfc\x5d\xd0\xa9\x99\x4a\xe9\x1d\xd1\xa2\x3b\xfa\x46\xf8\x3c\x5e\xce\x38\x18\xe2\xe7\x7b\xd1\xd2\x3a\x14\x18\xfd\x3c\x12\xa8\x8f\xeb\xe5\xb6\x67\x90\x88\x4b\x72\xf2\xea\x41\x88\x33\xb2\xb0\x27\x00\x0b\x7e\xfe\x9c\xd2\x2f\x82\x25\xa5\x2c\x79\xa2\xc5\x3d\xc8\x19\xdc\xfb\xe1\xc6\x9e\xb6\x8a\x38\x76\x63\x2f\x34\x44\x7f\xfb\xb4\x27\xeb\x96\xf3\x85\x7a\x26\xd8\xe2\x27\x35\x25\x60\x9a\xc9\xad\xff\x82\x2b\x95\xe5\x4b\x43\xd9\x7f\xf7\x09\xde\xe3\x91\x74\x37\x7b\x57\x15\x77\xe3\x9c\xfa\xf5\xb9\x47\x62\x9b\x64\xf6\xb6\x90\x30\x15\x63\x38\xc6\x6d\xe8\x8b\x57\xa8\x75\x1f\xdd\xab\xfc\x55\x9d\xc3\x3f\x95\xb5\x0f\xf4\x48\xd7\xd9\xdf\xfb\x33\xb3\xe7\x86\xd5\xd2\xae\x01\xfc\xbe\xd0\x70\xf7\xcb\x2d\xa2\x0c\xe2\x32\x2d\xcc\xf2\x69\x9e\x34\xdf\xd8\xf1\x33\x54\x84\xe3\x93\xff\x8c\x7a\xd0\x78\x34\x12\x78\xc8\x93\x33\xee\x4b\x2f\x5f\xc4\xed\xbf\x14\x56\xea\xde\xbf\x61\x99\xf2\x32\x96\x7d\xe6\xd7\xbf\xd5\xc2\xe9\x3f\x79\xfd\xf0\x16\x9e\x50\x1b\xb0\xaa\xca\xeb\x9d\xb9\x31\x26\x33\xd1\xca\xf4\xf0\x9a\x76\xeb\x76\xec\xcd\xfa\xbd\xa6\xc3\xaa\xf0\xba\xb6\xc5\x1d\x6f\x0d\xbd\xb3\xe3\x17\xa2\x03\x91\xe0\x48\xbf\x83\x61\xfd\xed\x0a\x92\x19\xf1\x65\x06\xdb\xc3\x04\xca\x1a\x58\xf8\xe3\x10\x00\x08\xd4\x93\xb9\x7a\x38\xac\xe3\x83\xf3\xfa\xcb\x6f\x12\xc2\xa7\xfa\xe0\x3b\x52\xf3\xb6\xfb\xf0\x05\x05\x77\x12\x77\xf7\x9d\xac\xd7\xf9\xb3\x78\xe3\x16\xf5\x7c\x60\xcb\x40\x44\xf7\xe4\xb3\xd9\xb2\x33\xb2\xe5\x1b\xe4\xc7\xb9\x77\x10\x6c\x27\xed\x39\x75\xe7\x52\xcb\xb0\x33\xae\xbf\x7b\x33\x19\xb7\xf0\x35\xd2\x47\x28\x88\x1e\x1d\x8c\x29\x46\x4b\x55\xa7\xe9\x47\xa7\x09\xd6\x11\x17\x35\x31\x32\xd4\x56\x3f\xcd\xff\x69\xf4\x88\xa8\x59\xce\xbf\xaf\xc2\x0f\xf9\xf9\x3d\xd0\x2b\xf0\xc5\x6b\xa0\x6b\x96\x0b\xf2\x39\x29\xf2\xc9\xb3\xe7\xd1\xdd\x5b\x17\x59\xf7\xea\x63\x7a\x0f\x6f\xcd\x3e\x3c\xd2\x98\xe8\x07\x3f\x3e\x14\xd1\x7e\xf8\x75\x18\xff\xfc\xc9\x4b\xa8\x12\x7f\x40\xaa\x46\xec\x3d\x34\xfa\xdd\xc4\xef\xc7\x77\xe3\x61\xf4\xc0\x96\xe4\xc7\x3f\xd8\xc6\x7f\xbc\xe1\xb1\x43\xdf\x1e\xc3\xd3\x2b\xf0\x34\x44\x8a\x59\xc0\xd5\xe8\x14\x8c\xd5\x33\xbb\xf4\x49\xe0\x3f\x0c\xce\x39\x70\xd1\x54\x37\xdb\xab\x95\xde\x4f\x5c\xf9\x69\x84\x7f\x0c\x0f\xe3\xc7\xb7\x57\x48\x26\x1c\x8e\xc6\x17\xeb\x07\x2e\x52\x9c\x52\xf5\xc6\xd4\xf7\xdb\x4c\x13\x0b\x28\x1b\xa8\x46\x6e\x5f\x86\x7d\x82\x29\xd4\xb1\x13\x7c\x27\xe7\xe7\xa9\xff\xca\xf3\x1e\x29\xe5\x41\x58\x50\xf9\x6d\x78\x3c\x9c\xfa\x6b\x18\xc9\x64\xa3\x97\x2f\x06\x29\x8f\xd6\x20\x92\xea\x1b\xaa\x50\x2e\x9f\x39\xbd\xce\xcb\x27\xfb\x95\xc7\x20\x60\x4e\xf2\x2e\x40\x26\xa5\x64\x10\xfb\xda\xb2\x34\x0e\x3c\x59\xad\x5a\x25\xf9\x8d\xdd\x75\x65\xb5\xae\x40\x9f\xd2\x07\xe2\x2f\xf2\xed\x7d\x09\x85\x6f\x72\xc0\xdb\xef\xd4\x2f\x0e\x93\xdb\x00\xf1\x9f\x5e\x66\xc6\x3a\xee\xd7\x09\x66\xa0\x68\x43\xc6\x4e\xc8\xde\x0d\x81\x42\xfd\xcf\x73\x71\xbb\x84\xef\x5b\x05\x63\x6f\x4e\x12\xb1\xac\x0a\xdd\xe4\x74\xd4\x3d\x07\xa5\x6d\xc8\xb7\x83\x30\xf3\xc8\xa6\x11\x69\x77\x36\xee\xca\x92\x5c\x9a\xdb\xd4\x0a\xf9\xd3\xc9\x99\x1f\x8b\xf3\x84\xaa\x8b\xaa\xa7\x33\xc7\x08\xb9\xdd\x43\x51\xfb\xb4\x19\xc8\xa0\x7e\x19\xff\x0c\x8d\xe6\x52\xb2\xaa\x19\xc3\xb1\xea\x72\x66\x31\x28\xe6\xe0\x0b\x84\x1f\x87\xf7\xbb\xcb\xb3\x55\x3e\x7f\xf4\x4c\x5e\xff\x39\x35\x69\x8d\xfe\x83\xe7\xca\xed\x09\x5d\xb6\xd7\xd6\xc0\x26\xb9\xc4\xee\x57\xe7\x21\xad\xdd\x47\xea\xd0\x85\x4f\x17\xc9\x08\x1f\x44\x4b\xfd\x1e\x46\xec\x9b\xf0\xd9\xd3\xe7\xaf\xa9\x3c\xca\x9f\xbd\xcd\x2c\xb6\xe9\x84\xc7\x89\x0b\x42\x1d\xc6\x5c\x3a\xdd\x1f\xcb\xd7\x3a\x8c\x37\x05\x82\xa7\x87\xd8\x99\x1d\xbe\xbe\xa2\x3c\x3f\x3e\xce\x1b\x5a\x2b\x0e\x24\x7d\xcc\xee\xb5\x67\x69\x58\x50\x07\xc2\x6e\x3f\xf5\x1f\x6f\x6d\xc2\x95\xfe\x3a\xb7\x7c\xe5\x73\x16\x28\x5c\x14\x67\xcf\x83\x69\xcd\xa7\x6c\xda\x72\x8a\x08\xb5\x2e\x4f\x25\x3f\x92\xd4\x7d\x07\x6f\xda\xab\x0f\x97\x49\x1e\xce\x07\x2b\x36\x9c\x3f\x3c\x37\xac\x8a\x80\x77\x8b\xcf\x9c\xcf\x8d\x4b\xe7\x69\x84\x52\x96\x6c\xa7\x31\x02\xbe\x9c\xe7\xf6\xc3\x4a\xd8\x61\x08\x3d\x70\x5f\x1a\xca\xa9\x97\x99\x17\xb7\x9f\xb7\x11\xef\x6e\x07\xf3\x96\xfe\x19\xa1\x4d\x3a\xca\x88\x36\xfc\xe0\x82\x9d\xee\xc8\x3a\xf5\x97\x96\x8f\xee\x92\xed\x8c\x19\xc4\xef\x2d\xbc\x6d\xfe\x13\x19\x88\x2c\x90\x73\x52\x1a\xdd\xd6\x21\x8f\xfe\xc6\x13\xe5\x30\x7e\x17\x0e\xcb\x8b\x8c\x95\x69\x72\x64\x03\xd7\x5c\x6c\x99\xe5\xbf\xbe\x93\x0c\x01\x48\xd7\xd4\xb9\xb0\x73\x67\xad\x9b\x7f\x50\xb7\xbd\xb6\xdb\xa4\x7b\xf5\xdf\x12\xd9\x72\x41\x7c\x75\xce\x09\xdc\x62\x32\xd7\xf0\x35\x96\x44\x50\x1d\x79\xee\xc6\x44\x30\x3b\x4e\x36\x3b\x96\x6f\x37\xfe\xa1\x51\x27\x76\x5f\xea\xdc\x4a\xa8\x35\x42\x4b\xb6\xaf\xea\xb8\xfd\x13\xbd\x09\x3a\xb1\xbf\x47\x25\x44\x11\xea\xfb\x56\xed\xc5\x4b\x0d\x44\xb0\xe3\x6b\x98\xbf\x9a\x74\x88\x97\x03\x46\xcf\x7f\xdd\xb2\xed\x56\x1a\xc2\xe6\x93\xbd\x72\xfa\x60\x12\x07\x30\x4c\x94\x35\x53\x8f\x1e\x40\x95\xf0\xff\x0b\x44\x61\x0f\xc4\x49\x53\xd0\xba\xdc\xad\xc5\x6e\x28\x81\x7e\xbd\x76\x37\x94\x27\x9d\x6a\x9e\x97\x13\xbf\x2d\x21\x28\x51\xf6\x22\x78\x3c\x1e\x17\x42\x1d\x2e\x31\x22\xf6\xa8\x6f\x4f\xd1\x13\xcb\x30\x49\xd1\x95\x63\xba\xb6\x20\xc8\x05\x89\x25\x6c\x50\xe2\x51\x92\xb8\x91\x70\x3f\x4f\xed\x89\x8a\x63\x44\xbb\xbf\x00\x35\x7b\x3d\xcf\x64\xa1\xef\xd9\x67\xd4\x35\x3c\x32\x37\x21\x49\xfc\x72\x8d\x14\xf9\x37\x43\x61\xf9\x43\xcf\x4f\x70\xd2\x31\x44\x0b\x5c\x79\xa9\xff\x3c\x42\x87\x4b\x32\x44\xac\xa5\x22\x19\x90\x91\x0c\xbe\xf2\x13\xdf\x47\x0e\xeb\x85\x0d\x7a\xc3\x87\xd2\xff\x46\x83\x1e\x6f\xdc\x11\xfb\x96\xe8\x1c\x28\xdc\xe7\x19\x73\x4b\xd2\xbe\x69\xe1\xd0\x44\x17\x33\xd4\xca\x1f\xbc\xf4\x32\x1e\xcb\x4c\x78\x77\x24\x5d\xca\x08\xc2\xcd\x7a\xa9\xad\x0b\x36\xc4\x34\x7c\xfa\x98\xa0\xf4\xf3\x13\x7d\xb8\x48\xf2\x7b\x00\xa9\xef\x48\x47\x14\x92\xc3\xd8\xf7\x10\x92\xc9\x7a\xec\xec\x9c\xd0\x58\x78\xca\xa8\xda\x21\x6f\xa6\x2e\xf2\x87\xd8\x22\xab\x78\x63\x57\x26\xe4\x7b\x94\x85\x53\xb3\x2b\x8b\x3d\x3e\x8f\xac\x52\x6d\xca\x9c\x88\x5a\x7f\x6e\x6a\xeb\xe8\xaf\x1a\x96\x3d\xaf\x36\x82\x67\x3d\xd5\x23\x7d\xd5\x93\x76\x2c\xaf\xde\xd3\xe2\xc9\xe2\x9c\x94\x7a\x19\x56\x18\x87\xa6\xfb\xcd\x8f\x00\xc2\x38\x51\x87\x21\xcc\x4b\x1d\xbd\x28\x81\x9a\xd6\x0f\x7b\x98\x05\xdd\x19\x3f\x4c\x14\xa0\xd1\x96\x14\xb9\x51\x45\xff\x6d\x75\x6d\xcd\x31\x8d\x60\x42\x9e\xc8\xfa\x91\xee\x6e\xdf\xe4\x45\xea\x4b\xf9\x82\xa2\x7e\xd3\x44\x44\x60\x7a\x61\xc3\x68\x81\x43\x9d\x96\xab\x02\x4a\x1e\x7d\xe4\x2a\x8f\xb3\x90\xc3\x0a\xfa\xd9\xcc\x51\xf5\x8b\xf6\xa5\xc7\xf4\x26\xd4\x03\x22\xb2\x3b\x04\x90\x12\xd7\x1f\x83\xf8\xd4\x2a\xa7\x6d\xa8\x01\xf0\x11\xb2\x28\x76\x3f\xa5\x77\x4a\x18\xf7\x1e\x76\xb0\xda\xa8\x7f\x37\x0e\x6e\x1a\xc0\xa1\xc6\x66\xee\x79\xd6\x2b\xcb\xdd\x7a\x65\x78\x49\x72\xe4\x25\xfd\xb5\x02\x13\x30\x09\xce\x99\xca\x3b\x6e\x80\x5f\xce\x51\x0a\x71\xa9\x6c\x33\xd4\x12\xf2\x1a\xfc\x0b\xda\x94\x80\x73\xd4\x21\xc8\x43\x6e\x27\xd6\x3d\xe6\x68\xc3\x20\x7b\x76\xc3\xb4\x34\x26\x24\xe2\x90\x42\x34\x67\x23\x82\x25\xa6\x5b\x83\x37\x00\xc7\xb6\xcc\x21\x95\x14\x0e\xba\xc2\x64\x1a\x5c\x9a\x76\xe1\x5e\x36\x27\x09\x95\x4c\xa1\x4d\xbc\xff\xad\x71\x41\x8c\xa5\x3d\xb7\xdd\x4e\x86\x32\xba\x9d\xb3\x07\x27\x22\xa7\x4a\x49\xf6\xaf\x42\x59\x0e\xe2\x05\x93\x70\xc0\x6a\x0d\x39\xf8\xf6\x69\x8a\xed\x53\x19\xa9\xee\x67\x6c\xd4\x3d\x41\xcc\x07\x28\x78\x48\xa2\xe9\xfc\xc5\xe5\x40\xc7\xa3\x3a\xe7\x45\xf6\xb2\x2b\x43\xce\x2f\xad\xc0\x9c\xd4\x12\x2e\x09\xa1\x9b\xc3\x87\xe8\x1e\x64\x25\x73\xfe\xc1\x97\xdb\x9a\x4a\x2a\x55\x17\x1b\x38\x98\xda\x94\x01\xa1\xd3\x54\x49\xfe\x0f\x96\xcd\xd1\x23\x99\x1b\xe4\x4b\x52\x46\x81\xc9\xdd\x99\x4a\x0f\xe6\x99\x48\xf9\x93\xc7\xca\xbf\x32\x81\x79\x1b\xe1\x65\x98\xdc\xd5\xd6\x10\xc1\xd1\x9c\x32\x5c\x1d\x07\x10\xa4\x73\x94\x9b\x33\xf2\x2c\x66\x9c\x3e\xf4\x30\xb1\xda\x84\xb2\x21\x83\x41\xbd\xcd\x74\x19\xd1\x7f\x4f\xd8\x4e\x24\x6d\x43\x58\xc4\x36\xb5\x29\x53\xc1\xa8\xd8\x84\x92\x09\xfe\x8a\x1b\x66\x75\x30\x3c\x8d\xd5\x87\x1d\xf7\xdb\x28\xd0\x1f\x46\xe2\xf4\x4f\xcd\x3a\xae\x21\x02\x83\x12\x77\xcc\x44\xcc\x7d\xcb\x11\xe5\x5a\x1e\xe5\xf6\x28\x54\x20\xc3\xfd\x5a\x2b\x9c\xad\x16\x29\x02\xf1\xe1\x20\xae\x67\x07\x82\xf5\x29\xcb\xb6\x05\x66\x9a\x41\x1a\xed\x01\x93\xb3\x15\x19\x32\x20\x2c\x86\x0d\x5e\x6f\x4e\xb2\xaa\xe5\xbf\x8c\x70\x51\x24\xc7\x7e\xc1\x80\xe6\x6b\xc7\x34\x1e\x37\x0b\x08\x16\x8c\x42\xb2\x49\x09\xbe\xd4\xdc\x9b\x6c\x97\x7c\x70\xf8\xda\x0f\x81\x09\x10\xbc\x1a\x34\x2a\x13\x5a\xe7\x64\x95\xba\xfe\x42\x3d\x49\x83\x27\x68\x3e\x56\x23\x43\x19\xc4\xc1\xbe\x89\xab\x1a\xa5\x92\x52\xdf\x28\x30\xb6\x46\x59\xab\x4e\x51\x89\x37\x91\x27\xe5\x12\x15\x9e\xc2\xc3\x9c\x08\x01\xa9\x08\x80\x21\x9d\x07\x49\x08\x46\xd9\xee\x83\x45\x1a\x65\x08\xe4\xd9\xa2\x20\x4f\x36\x9e\x4c\x56\xc1\x73\xee\x51\x97\xbd\x12\x8c\xf6\xee\x32\xbf\x6c\xa6\xc3\xcf\xb7\x4a\x30\x38\x4d\x86\x08\x88\x33\x12\xd2\x61\x0f\x84\x10\xc1\x99\xbd\x05\x46\xc2\xc8\x87\x24\xb0\x2d\xce\x07\x6e\x14\x53\xc8\x92\x76\x27\xc1\x65\x1b\xa0\xe6\x5c\x69\x1a\x64\x39\xd4\x57\x8a\x76\x80\xcb\xe6\x4d\xd6\xff\x12\x52\xc3\x8b\x57\xb3\xa2\xd6\x86\x68\x63\xd7\x90\xe0\x69\x29\x6c\x8f\xf1\xb5\xa1\x90\xad\x17\x94\x57\x7b\xd0\xe0\x48\xd1\xbb\x2a\x4c\x43\x60\x15\x14\xb4\x7d\x87\x82\x80\xc0\xa5\xff\x3c\x1f\x2d\x72\xb9\x5f\xce\x56\x27\x28\x48\x8f\x40\x27\x97\x42\x8a\x48\x3f\x00\xea\xf2\x60\x8b\x1b\xac\x9f\x99\x55\x90\xe8\x8f\x93\xad\xc6\x34\xf3\x24\xb1\xec\xe7\xb7\x7f\x38\xc4\x8d\xce\x6e\x0a\x00\x2f\x74\x87\x95\x55\x22\x70\x13\xc3\x7b\x70\xd3\xa1\xdc\x0b\xb5\x83\x31\xaa\xa3\x41\xaf\xcc\x66\x44\x2f\x62\xba\xc0\xcf\x21\x8b\xaf\x95\x61\x3c\xc7\xaf\xd0\xe6\x04\xf5\xa1\xfe\x80\xa5\xb6\x59\x16\x56\xef\xbd\x64\x47\x0f\xeb\x46\xc0\xcb\xd5\x28\x2a\xa3\xbc\x8a\xc7\x24\xa4\x62\xc8\x9c\x60\xf4\xf9\x86\x08\xde\x20\xc6\xbb\x29\x7a\xfe\x75\x27\x3d\x94\x9a\xbd\x01\xed\xe0\x05\x20\xf0\x38\x40\x58\xa7\x20\x83\x4d\x95\xd6\x7e\xf9\x90\x28\x21\x38\x49\xa4\x2c\x82\xfb\x07\x1e\xe0\x63\xed\x1e\x23\x0d\xdf\x9a\x43\x2a\x9b\x63\xca\x43\x78\x88\x51\x94\x23\xca\xd1\x82\xc4\x12\x03\x17\x6a\x85\xfa\x85\xd1\xc2\x2e\xa7\xa7\x2c\xf7\x48\x11\x77\x60\x83\xd5\x36\x82\x16\xcc\x1d\xd6\x87\x67\xd3\x3f\xdb\x28\xa8\x60\x84\xdb\x30\xb4\x2c\xcf\x63\x59\x05\x2a\xc6\xce\x23\x00\xb3\x5c\xe7\xb9\xde\x3a\x2b\xc8\x4e\x8c\x03\x64\xea\x7f\xc9\x6b\x94\x5d\x77\xfb\x9a\x8d\x0b\xab\x7c\x3a\x35\xc0\x07\xc1\xda\x1e\xb6\x9b\xb1\xd1\x30\x14\x90\xe1\xff\x08\xb6\xdd\x21\x2e\xc1\xef\x05\x08\x4d\xfa\x29\xb0\x86\x23\x7b\x57\x26\xc6\x67\x28\xce\x3a\xc3\x8a\x48\xd7\x4c\xaf\x99\x9e\xfa\xde\x83\x58\xcf\xa7\x80\xec\x62\x12\x80\xc5\x65\x80\x59\x14\x3b\x88\x41\xa1\xba\x05\x45\x96\xd6\xe7\xcc\x76\x0e\x09\x58\x04\x3d\xe5\x10\x19\xf5\x9f\xb0\x48\xc7\x15\x06\x2b\xe7\x97\x56\x50\xf0\x02\x49\xdb\x61\x78\xa5\x12\x50\x75\x0b\x08\x7e\x2d\xa3\x31\x91\xa1\x68\x35\xa7\x87\xbb\x88\x13\xcd\x49\x2e\xaa\x6b\x56\xae\xf8\x32\x97\x81\x16\x9d\xf6\xe0\xed\x8a\xac\xc3\x13\xf0\x4b\x94\x93\x9c\x77\xa1\x9b\x18\xf8\x2b\x9f\xf1\x0f\xe8\xc6\xca\x1f\xb3\x06\xa3\x1b\x14\x39\xe5\x23\x84\x33\x41\x1c\xce\xfa\xeb\x38\x28\x6e\xd8\xf0\xe5\xa6\x75\xf8\x4b\xa2\xb8\xd4\xd4\xe9\x5d\x35\x30\xea\xec\x5b\xcc\x4f\x48\x3f\xce\x6d\xef\x56\x33\x77\xb0\xd1\x49\xb6\x88\x14\xe1\x49\x63\x9a\xe4\xc5\x53\x92\xd8\x77\xe6\xa9\x05\x93\xc1\x6e\xc1\x49\x39\xfa\x3e\xb3\x28\x06\xc1\x1f\xe0\x8b\x31\x11\xf1\xca\xd6\x7d\x60\x08\x78\xe6\x22\x5c\xde\x38\x54\xd4\x32\x59\x29\x5c\x1b\xc3\x92\x1c\xc2\xbd\xd6\xdf\xd6\x97\x98\x09\x39\x8b\xb8\x28\xe1\xdd\xe5\x93\x43\x97\x26\x50\x65\x30\x5e\x82\xda\x06\x38\x60\xe9\xfd\x8c\xf3\x98\x2e\x0d\x62\xe1\x20\x59\x93\x91\x6b\xe7\x8f\xea\x3a\x2b\xaf\x89\x3d\x91\x46\xc4\x25\x84\x13\x2a\x83\x72\x14\xc0\xb1\xd4\x26\x9a\x24\x90\x69\xc4\x65\x08\x87\xa3\x79\x62\xc0\x3a\xf7\xa1\xc2\x0a\x48\x68\x3c\x81\x66\xed\x6d\x35\x0b\x95\x3e\x31\xc3\x96\xb9\x5f\xe4\xc7\x86\xff\xa6\xb9\x4a\x55\xed\x25\x6a\x21\x1b\xf5\x67\xd7\x82\x11\x9f\x41\x7a\x4d\xac\x2e\x34\xb4\x5d\x30\xfd\x26\xaf\x15\x97\xaf\x9a\xe6\x43\x62\xaf\xb8\x67\x49\x17\x15\x75\x0c\x49\xf9\x2c\x38\xa4\x46\xd3\xda\x41\x2c\x90\x39\x29\x26\xb3\xa5\x4d\xd2\x8b\x68\xe2\x56\x0a\xb9\x56\x15\x8d\x23\x12\x28\x48\x05\xc9\x83\xdb\x36\x0d\x5e\x46\xb9\x92\x28\xe0\xa2\x09\x08\x78\x8c\x8f\x42\x54\xb3\xc7\xcd\x1a\xe9\x70\x59\xe7\xec\xe3\x0e\x85\x90\x3e\xfb\x56\xc9\x90\xe2\x6e\x63\xc0\xc6\xdb\x20\xf3\x69\xbe\x55\x29\x6f\xdc\x62\x4f\x0c\x29\x27\x27\xe3\x3e\xf7\x0b\x8a\x12\x8d\xe9\xef\xea\x89\x47\x48\x66\xb5\xb1\x59\x51\x4d\x47\x18\x82\x21\x56\x0a\x57\x05\x25\xaf\xb3\x85\x21\xa0\x89\xf5\x47\xe1\x0f\xbc\x2e\x3f\x23\xa0\xf1\x5c\xe2\x23\x42\xe6\x8c\xc9\x05\x6e\xa5\x68\x98\xe5\x8f\x74\x0a\xa3\xd8\xd2\x1e\x5b\xea\x9e\xd1\xf8\xb3\x4d\xb0\x60\xc2\x21\x63\xc2\xba\x56\x20\x7a\x6b\xcb\xe8\x14\x62\xdc\xa5\x00\xb9\x62\x2c\xca\xdc\x7f\x41\x02\xe1\xef\x47\x7e\x16\x28\xcf\xfd\x70\xca\x03\x6b\x93\x25\x59\x05\x07\x85\x9c\x0c\xb4\x30\xa7\x6c\x34\x3f\xcd\x0d\x40\x3a\x05\x80\x5a\x81\x48\xb5\xd1\x3b\x24\x73\x7d\xe3\x4b\x57\xe5\xa4\x77\xd5\x66\x6a\x02\x9f\xde\xf5\x74\x42\x51\xc3\x81\xd6\xc5\x3e\x9a\xc4\x26\x10\xa3\xba\xa7\x8d\x10\x35\x92\x74\x45\x41\x5f\x35\xab\x62\xca\x0c\xb6\x01\x1c\x7d\xc9\x85\xf2\xb8\xf0\x05\x4a\x45\x51\x45\x67\x24\x10\x8b\x58\xcd\x44\x06\xbb\xfc\xc1\x20\xeb\x38\xea\x05\x94\x2a\x55\x9e\x32\x80\x92\xd8\xd5\xe7\x39\xfa\xb4\x0e\x4c\xae\x3a\x22\x35\x15\x93\x43\xdb\x41\xf8\x60\x93\xc0\x60\x14\x0f\x9d\x28\xe1\xa2\x88\xe7\x54\xe2\x20\x37\xf3\x59\xe6\x45\xd7\x10\x4f\x73\xa5\x81\x66\xdd\xf8\xd1\xd3\xc7\xe5\x2b\x27\xe6\xec\x29\x48\xdc\x7a\xdc\xbb\x00\x50\xc4\x2f\x08\x1b\x05\xd4\xb4\x20\xe8\x4a\xb4\x57\x8d\xb9\x27\x99\x54\x1a\x1b\x50\xb8\x3a\x74\xab\x7f\xf9\x20\x27\x22\xaf\x44\x1d\x32\x90\xcb\xd4\xe0\x9c\x79\xe8\x41\x87\xf7\x9e\xb5\xe5\xbc\xcc\xca\x17\xcd\x99\xc1\xb4\x0f\x06\xec\x5b\x82\x43\xba\x95\x69\xe6\x0d\x86\xf7\xbe\x57\xa2\x18\x8b\x89\x15\x72\x77\x78\x5c\xc4\xb5\xe4\x1f\xc5\xb9\x9d\x44\xfd\xe5\xc4\x1e\x6a\xda\xc2\x61\x5d\x67\x68\x92\xfa\x0a\x92\xdf\x66\xf0\xa6\x47\x05\x8e\x42\x04\xe6\x93\x06\x48\x2e\xb7\x06\xa9\xaf\xbe\x89\x5c\x47\x42\x68\xce\x73\x3c\x73\xa4\x4a\xbb\xac\x7d\x06\x20\x9f\x4a\xab\x87\x6e\xc3\xb1\xef\x16\x53\xd7\x9a\xd8\xf8\x39\x69\x59\xd8\x85\x42\x3b\xf6\xa3\x82\x2a\xbf\xee\xbc\x18\xff\xad\xc2\x2c\x4f\x3f\x66\x7f\xe2\x0c\xc1\x67\x54\xc5\x9f\x4d\x70\x85\x0c\x0d\xed\xd9\x61\x7d\xcd\xd9\xd0\x66\xc2\x37\xf6\x85\x6b\xa8\xab\x00\x2d\x26\x68\x76\x00\xa1\xa0\xdc\xea\xca\x0c\xea\x68\xae\xc7\xc2\xe7\x09\x43\xb6\x1b\x21\x0c\x90\x0b\x82\xb8\xc1\x6e\xdb\xed\x15\xdb\x32\x23\x52\xeb\x51\x62\xab\x2c\x1b\x01\x7f\xaa\xc9\x29\x44\x0e\xb9\xd3\x39\x14\xe9\xce\xd5\x1f\x99\x0d\x89\x76\x7a\xff\xf0\x4d\x4b\x84\xd2\x4f\xa2\x05\x76\x2b\x07\xae\x00\xda\x45\xe9\x91\xb1\xc2\xce\x81\xf9\xf6\xe0\x5d\x82\x79\x38\xf6\x1c\x61\x19\x76\xf6\xb3\x63\xbb\x98\xc5\xc6\x98\x1b\x10\x8a\xf4\x1a\x31\x4c\xc9\xe4\xfe\x26\x70\x34\xa6\xd2\x67\x8d\xdf\x1a\xa3\xf4\xcc\xe4\xe3\x1e\x92\x36\x83\x21\x73\x99\x3d\x52\xea\xbb\xd1\xe1\x62\xe2\x9e\x7d\x68\x56\xfb\xa6\x8c\x1c\xd2\xae\x8e\xd2\x5c\xec\xee\x35\xbb\x2a\x09\x72\xf8\x31\xfe\x08\x7d\x3e\xb4\xdf\xa3\xcc\x86\x7c\xed\x20\x2e\xff\xc6\xeb\x52\x93\xde\xc3\x92\xd0\xaf\xe8\x5f\xd3\x72\x02\x0b\x02\xee\x7c\x65\xca\x2a\x40\x2c\x2a\x91\x6d\x91\xab\x59\x04\x1f\x87\x36\x31\x7b\xcb\x7a\x5f\x45\x22\x45\x60\xda\xb5\x81\x50\xb6\x8f\xf7\x3d\x58\x20\x70\xb4\x86\x78\xbe\xb4\x53\x44\x86\x38\x3d\x58\x2d\xf3\xc1\xaf\xf5\x28\x83\xeb\xbf\xb7\x71\x09\x23\xbc\xf2\x61\xc3\x34\xf0\xf4\x44\xc0\x0a\x85\x21\xdb\x45\xb6\xec\x16\x71\xee\x3b\xa4\xfb\x49\x7d\xfb\x48\x47\xc3\x8e\xd0\x22\x80\x87\x5c\x9a\x96\x81\x81\xb2\xa2\xaf\xca\x48\x71\xca\x24\x24\x07\x0d\x02\xa7\x61\xed\x00\x95\xa4\xbf\x88\x3c\x06\xae\x15\x02\x96\x08\x3c\x42\x57\xf7\xeb\xa0\x31\x93\x66\x63\xdb\xf2\xe7\x41\xb3\xf4\x2a\x96\xaa\x54\xba\xc2\x66\x89\x36\xab\xa1\xa1\xf1\xdd\x21\x39\x0e\x81\x1c\xb9\xac\x86\x29\xde\x1c\xe8\xbb\xf1\x34\x45\x28\x55\x41\xe4\x54\x82\xac\x28\x7f\x9a\x38\x6c\xb3\x34\x25\x0b\x1a\xcc\x1f\x3b\xde\x53\x2a\x54\x65\xa6\xe3\x67\x15\xb5\x15\xdb\x09\x80\x43\xaf\x47\xe4\x5c\xfd\x70\x01\xe7\x36\x94\x69\xc7\x32\x60\x0e\xf8\x10\x0d\x0a\xe9\x93\x0c\x18\xcb\xe0\xfd\x41\xa6\x29\xee\xe1\x17\x47\x89\x43\x93\x9b\x11\x4a\x41\x66\x70\x55\xc5\x7d\x16\x25\x7f\x78\xbd\x3d\x9d\x9d\x76\x93\x82\xa5\xb7\xc6\x0d\x72\xe0\xd9\x03\xd4\xab\x4d\x2e\xc3\xcf\x35\xdb\xee\xc0\x86\x82\x8e\xdc\xf4\x52\x90\x30\xfa\x30\x06\xec\xd3\xbf\x69\x08\x12\x64\x42\x22\x44\x11\x25\x49\x64\xf7\x65\x41\x93\xb2\x57\x48\xfe\x14\x36\xd9\x77\x88\xee\x74\x68\x00\xac\xb5\x9d\x8c\x55\xf8\xae\x81\x77\xc0\x06\x09\x09\x66\x69\x64\x9e\xd6\x12\x89\x3f\xc1\x91\x49\xe0\x91\xa0\xc6\xd0\x39\xcd\x11\xa4\x7f\x92\x45\xc5\x35\xd7\xf5\x3f\x67\xdb\x09\x69\x74\x96\x37\x32\xf1\x80\x0c\x05\x14\x86\x63\xdb\xa6\x67\xe1\x6b\xd1\x3e\x60\x8c\xa7\x20\x9d\x8d\xa0\x85\xa2\x28\xd8\xf9\xfe\xd2\xd4\xee\x52\x6f\xb6\x6e\x0e\x7e\x38\x18\x44\x83\x51\xce\x73\xb8\xaf\x68\x15\x43\x55\x12\x54\xaf\x26\xa8\xde\x0c\x33\x62\x3a\x96\x58\x4b\x73\x18\x4c\x45\xf6\x6c\x4e\xe9\x7f\x76\xe0\xf9\x6c\x01\x03\xe1\x42\x2b\x97\x90\x08\x90\x80\x0f\x68\x3c\x71\x86\xea\x74\xeb\xcc\xf7\x7b\xa8\x2d\x77\x21\x31\x16\x19\x5e\xd6\x43\x50\xce\x26\xa9\x86\x64\xc3\x2c\x76\x85\xe4\x6b\x4c\x17\x08\x69\xc1\x46\x0a\x4c\x28\x7c\x63\x4a\xf3\xd1\x48\xb6\xfc\xa9\x66\xa2\xdb\x82\xf5\xd5\xf5\x39\x14\xd7\x47\xc3\x25\x4f\x52\x52\x1d\x46\xc3\x30\xb7\x84\x46\xd2\x31\x5c\xb6\x79\x24\x69\xc9\x4c\x3c\xaf\x61\xf2\x79\xf0\xf8\xc6\x68\xf2\x66\x5c\x24\x35\x02\xfb\xe0\xea\x21\x9a\x45\x1a\x80\x4e\x41\x01\x17\x81\xf3\x12\xf1\x68\x73\x7a\x34\xf1\x93\xb1\x1e\xa0\x1a\x0a\x28\x3e\x43\x3f\x7b\xef\xd7\x31\xa5\xde\x71\x22\xba\x6e\x72\xf4\xc5\x88\x03\x54\x4f\x09\x6a\x48\x3c\x3e\x15\x84\x09\xfb\x40\x31\x46\xbf\x8d\x30\xce\x04\x13\x40\xb2\xd0\xd1\xab\xa3\x5a\xa2\x11\x86\x60\x45\x5f\x82\x18\x52\xe2\x38\x9f\x52\x14\xfb\x83\xc8\x8d\xbb\x2c\xa4\x3c\xd1\xc2\xdc\xb7\x8d\x80\x98\xe2\x73\x74\x54\x7c\xa4\x09\xc1\x1c\x59\xba\x87\x81\xc6\x6b\x32\x9c\x89\x04\x4f\x15\x7b\x41\xb5\x80\x51\x57\x7a\x10\x33\xe8\xc5\x30\x27\x0f\xbb\x06\x53\x79\xab\xac\x34\x2a\xde\x6a\x6e\x8e\x08\x1d\x14\x5d\x3c\x4c\xc7\x6d\x43\x3b\x96\xfb\x71\x4d\xcb\x0b\x68\x7f\xa3\x8f\x56\xe7\x93\xc1\x74\x74\x12\xc6\xdb\x2e\x81\x34\xa6\x1c\xca\x87\x67\x9a\x90\x52\xa4\x93\xf8\x89\x91\xbc\xfa\x27\xcb\x1b\xdd\xad\x8d\xb1\x1e\x54\xf4\x11\x84\x67\xbd\xa8\x26\x7c\x03\x39\x02\x35\x2b\x9f\x91\x12\x68\x2b\x6c\x1a\x61\x0e\x86\xb6\x36\xeb\xf9\xee\x0b\x9f\x43\xe2\xc0\xd1\xac\xc9\x72\xf2\x6f\x5e\x46\x9d\x08\xaa\x3b\x2a\xf7\xb3\xaf\xba\xc0\x9c\x94\x86\xff\x9e\x09\x24\x9b\x9e\x05\xfc\x24\x9b\x5a\x44\x2f\xb1\x21\xb9\x52\xb4\x06\x52\x1c\xe1\x54\xe9\x16\x7b\x15\x3c\x0d\x81\x28\xa0\x36\xff\x77\x61\xaa\x99\x08\x88\x00\x6b\x70\xe9\x95\x62\x1d\x54\x5a\x73\xea\x24\x15\x5d\x0b\xe3\xb9\xe0\x87\xd4\x20\xcc\xf9\xbf\x3c\xf2\x2b\x08\x25\xde\x79\x0f\xb2\x32\xa8\xab\xdf\xa4\x37\x54\xa3\xf9\xb8\x05\x6f\xb8\x6f\x6e\x88\x1e\xe0\x58\xb3\xd0\xa3\x7f\x51\x98\xe8\x1f\x33\xb2\x34\x84\x9b\xc5\x8e\x20\x57\xa1\xa1\x85\xda\x8d\xb4\x2a\xb1\x46\xf3\x98\x7b\x21\xd5\x89\xdf\x03\x5e\x48\x46\x61\xe5\xc1\x72\xcb\x9b\x15\x87\x0a\x65\xa7\x3d\xc7\xbe\x6d\xde\x8f\x1b\x36\x42\xba\xe7\x82\xbc\x06\xd5\x5b\xc1\x72\x18\x31\xdf\xe8\x0b\x2f\xad\x1c\xc3\x18\x7d\xfa\xdc\x4d\x2a\x41\x9b\x4e\xfd\x50\x3f\x86\x83\x2d\x5c\x35\x4d\x6c\x36\xc7\xfd\x58\x4b\xfb\xc8\x9d\x0d\xb6\x4f\xd1\xca\x72\x86\x2e\xe1\xcd\xd8\x1a\xf3\x9e\x76\xfb\x77\xb6\x2e\x41\x71\x57\x69\x67\x91\xa2\x45\x25\x5a\xe7\xc2\xf2\x2b\x54\x70\xd3\xa2\x96\x1f\xc9\xbb\x14\x13\x8a\x47\xc1\xa1\x38\x93\x0d\xaa\x7b\x94\x23\x22\xc4\x31\x82\x9c\x82\x33\x3d\xc9\x46\x91\x98\xf2\xbc\xac\x41\x3b\xe0\x24\x5b\x43\x86\xe3\x4d\xcd\x41\x95\x8d\xcf\xc0\x0f\x9a\x7f\xd7\x8a\x03\x57\xe9\xc0\xbc\xe7\x1a\xb0\x52\xe8\x69\x91\x53\x7e\xdb\xb4\x29\x56\x09\x84\xc9\x30\xda\x99\xdf\x3e\xb6\xb0\x11\xf2\x2b\x00\xe9\xa3\xcc\x59\xdd\xf1\x27\x4b\x31\x29\xc5\xa0\x67\xf2\xba\x72\x8d\x04\x26\xc0\x64\x1a\xb3\x8f\xf7\xbb\x23\x53\x1a\xfb\x56\x94\x38\x47\x69\x1a\xd1\x5b\x6c\xb4\xe8\x15\x4f\x4e\xaf\x9f\xc3\xf5\x87\x0b\x7e\xb4\x6b\xdd\x20\xd6\x97\x28\xd8\x3f\x07\xfe\x58\x43\x0a\x06\xc6\x75\x21\xd7\xe8\x82\x1b\x87\xbb\x62\x85\xfc\x10\x71\x62\x10\x48\x4a\x53\x2a\x3a\x6d\x30\x21\x21\xdc\xa3\x79\x40\x75\x90\xf1\xc6\xa6\xd8\x6a\xad\xef\x41\xc8\xd6\x50\xac\xb5\xa8\x4a\x15\x29\x48\xa8\x22\xf2\xf7\x61\xd7\xc1\xe3\x99\x62\x8e\x86\xa4\x10\xbe\x80\xc9\x4b\x13\xee\x2b\x71\x3f\xec\xe7\x45\xfc\xf0\x17\xf6\x16\xf6\x88\x08\xcf\xcb\x31\x33\x37\x6b\x87\x6a\x45\x12\x5c\x9a\xe7\xe1\xfc\xd9\x19\x90\xfc\x13\x46\x33\x5c\x82\x7d\x45\x90\xc2\x44\x8f\xd8\x42\xdb\x12\x4e\x65\x09\xde\xd3\xf3\x81\xce\x62\xb1\x23\x3b\x2d\x3b\x81\x13\x08\x4d\x46\x02\x2f\x71\x59\x6b\x44\xb8\x3d\x40\x35\x21\x70\x2f\x2b\x86\x9e\x19\x02\x4e\x26\x72\xc3\xc7\xbb\x29\x74\xf6\x36\x42\x00\x39\x0e\xa3\xb3\xff\xec\xe6\x95\xa6\xf4\x87\x47\xe0\xe8\xda\xbb\x53\xc4\x25\xad\x63\x6a\x10\x31\x38\x80\xe7\x96\x3c\x9c\x08\x32\x35\xe8\x9e\x0e\x05\x09\x9d\x24\x51\x72\x05\xa6\x45\xb1\xb8\xbd\x88\xf0\x09\x5f\xcc\x33\xb4\x84\xfe\x1c\xed\x41\x3a\x90\xa6\x7f\x5b\x0e\xd0\xac\x12\xaa\x3a\x2d\xf0\xfb\xce\x98\x22\x10\xb3\x7f\x4f\xad\x4b\x59\x80\x5a\xa5\x12\x69\x58\xa2\xbd\x37\xe4\x7e\xd1\xa9\x4f\x58\x27\xe7\xdd\x15\xf3\x9f\xe1\x9d\x8c\xc7\x39\xf6\xa4\x52\xbc\x46\xc5\x61\x11\xab\x20\xf7\xcf\xa9\x64\xa2\xb7\x9e\xa1\x18\x1a\x8d\xe2\xa6\x41\x52\x4a\x11\x3c\x96\x0a\xef\x39\x0f\x89\x81\x00\x1d\x1e\xbb\x6f\x44\xf7\x80\xb2\xa0\xf0\x01\x04\x34\xb6\x20\x09\x8c\x2e\x89\xac\x52\xb9\x7c\x10\x50\xad\xa7\x1f\x5e\xb4\x61\xb1\x20\x9d\xbb\x73\x08\x66\x24\x53\xaa\xe0\x42\x3b\x76\xdd\x1e\x40\x7a\x7a\xd2\x65\x11\xd4\x4c\xa0\x01\xb1\xba\x77\x9d\x93\x63\x4b\xa5\x08\x4e\x45\x83\xb1\x38\xc2\x2d\x35\x0a\xea\xe1\xcf\x6f\xd2\x8f\x53\x37\x22\x18\x29\xeb\x2f\xa2\x10\x58\x59\xd6\x5c\x4c\x6d\x4e\xd2\xd7\xf0\x71\xba\x59\xbd\x87\x05\x62\x84\xde\x6a\xd0\x3f\x9b\xbd\x69\xa3\x6b\x06\xca\x4c\xca\x8f\xe7\xd8\x3c\xee\x12\xb6\xdf\x72\x22\x54\xdb\x32\x76\x9c\x94\x6f\xe9\x8f\xac\xad\x13\x1e\x1b\x17\xda\x65\x45\x43\x65\xf4\x18\xee\xca\x55\x30\x74\xfd\xe8\x8c\x18\x0f\xc2\x8c\x6f\x5c\x78\xd5\xd2\x84\xfc\xcf\x13\x43\xb3\x19\x3f\xb8\xb0\x3f\x11\xae\x76\xf1\x59\x8c\x47\x23\x9c\x6e\x44\xeb\x31\x85\x2c\x81\x22\xad\x08\xec\x7e\x72\x7d\x3b\xa8\x93\x60\x4c\x4f\xb5\x97\xf9\x26\x8c\xfd\xe1\x63\x99\xc2\xb3\x50\x38\x9e\xcb\x5d\x8f\x01\x9c\x05\xa8\x50\x08\xfe\x07\x12\xc6\x50\x0b\x60\x47\x4f\x2d\xcf\x6d\xee\xca\xfb\x0d\x20\xac\xe0\xb8\x52\x14\x9e\x06\xd3\xdf\xb2\x04\x5f\xb0\x4e\xd3\x50\x11\x64\x6e\xae\xfa\x57\x4e\x2e\xc6\xb7\x8e\x90\x4e\xae\xb0\xfb\xb5\x27\x98\xd8\xba\xad\xd8\xb0\xe4\x09\x4e\x6e\x82\x0e\x82\x40\x74\x96\x5f\xf0\x27\x78\xd3\x18\x7d\x2b\x58\xda\x3e\xa8\xaf\xbb\x9f\x8d\x6b\x53\x14\x29\x64\x4f\x87\x86\xe0\x04\x6f\x10\x1a\x0e\x47\x94\xb1\x0c\xef\x38\xb6\x6b\x52\x53\x5b\x4f\xf1\x63\x9b\x98\xfb\x78\x19\x1a\x80\x14\x31\x4c\xbd\x4d\x5f\x24\x0e\x26\x37\xc3\x14\xa0\x3f\x84\x45\x42\x15\x83\x3e\x6f\x5a\xbe\x96\xa2\x60\x27\x23\x27\xdf\x5f\xbf\xa0\xfa\x91\x84\x25\x96\x0d\x11\x50\x58\x5d\x0f\x60\xb6\x95\x70\x3a\xe8\xe5\x6d\x7f\xf3\xb4\x7d\xc0\x24\x9c\x85\x7b\x7b\xb0\x18\xad\x92\xec\x66\x1f\x8e\xb2\xa7\x00\x1f\xa3\x24\x22\x84\xd8\x87\x74\x27\x72\x27\x71\x95\x83\x0e\x22\xb1\x5a\x86\x8c\xb5\xd4\x69\xa5\x1f\x5d\xa7\x4b\x80\x61\x6f\x35\xa7\x44\x0a\xb4\xae\xb5\xdc\x79\x92\xc8\x72\x29\x20\x01\x4c\xa7\xa3\x55\x12\x60\x62\x68\xce\x47\x17\xe2\x33\x1b\xb8\xdb\xf2\x00\x76\xc3\x3b\x6b\xec\xb3\xd9\x57\x9f\x58\x23\x3b\x32\xa9\xcd\x5b\x65\x3d\x59\x5d\x5c\xe8\x54\x26\xd8\xa8\x22\x3e\x80\x56\x66\x87\x50\x5a\xef\xbe\x88\xe0\xc8\xcb\x71\x43\xf4\x17\x6b\x68\x03\xc9\xc8\x43\x34\x1e\xfe\x09\xa1\x16\xa7\x82\xf3\x5b\xbc\x0b\x4e\x14\x31\xf4\x75\x7d\x7d\xbf\x64\xf0\xdc\x7b\x4f\x49\xa7\xc4\xba\x0a\xc2\xfa\xe5\x69\x14\x10\x43\x04\x20\xc7\x11\xa9\x0e\x8a\xe9\xb1\x0a\x8e\xe3\xcf\x1a\xaf\x94\x71\x3b\xf5\xb6\x2d\xfe\x4c\x4d\x6c\xcd\x41\x80\xb4\xa8\x56\x7c\x41\xdc\xd6\x2a\x8f\xba\xdb\x46\x85\x09\x00\x5d\xba\x88\x32\x1f\xeb\x08\x23\x77\xcc\x34\x8e\x4c\x6b\x24\x4e\x81\x6e\xbb\x89\x1f\xd3\xde\x7e\x1f\x7e\x7e\x66\xdf\x5b\x21\x93\xe5\x3e\x1f\xf3\x49\x1f\xaf\xa0\xe3\x2b\x69\x1d\x3b\x3b\xb2\x09\x81\xae\x71\x75\xbb\xe7\x7e\x57\xa3\xdf\x77\x29\x9b\x1f\x7e\xa6\xab\xfc\x3f\x75\x84\xc7\x17\xff\x56\xcc\xcf\x76\x10\x0b\x67\x26\xad\x90\x72\xca\xeb\xba\xca\x6e\x5f\x41\x5b\x7a\x7c\x5e\x9f\x74\x25\x5e\xae\x60\xa7\xf3\x76\xb8\xe8\x67\xee\xf2\x76\x6a\xe6\xda\x14\x7e\x30\xfd\xf2\x9d\xef\x95\x02\x62\xa4\x01\x00\x34\xa6\xff\x58\xef\x4d\xdc\x2d\x4c\x01\x00\xf3\x80\x9c\x4c\x33\x47\x72\x2e\xd7\x90\x1f\x23\x74\x2d\xd0\x6e\x4d\x84\x49\xd1\x60\xd7\xfc\xa3\x8b\xdf\xee\xc5\x91\xaa\x5b\x35\xe9\xd8\x8d\x17\x19\xc6\x14\x28\xed\xc7\x58\xc6\xbf\x3f\xf2\x7e\x7a\xae\x7b\x5f\xc7\x7c\x58\xd3\xa4\x2f\x5c\x16\xcf\xdf\xc6\x28\x09\x6f\x0e\x1e\xf3\xf2\xa6\x7b\x8f\x85\xc3\xbb\xcb\xea\x8c\xf6\x2e\x08\xeb\x04\x4f\x52\x6e\x0e\xae\x1f\xf4\x48\xfd\x34\xf8\x7f\x6e\x5d\xbc\xdf\x91\x3e\x08\xc1\x86\x66\xca\x1e\x2f\x58\xec\xf4\xc1\xd8\x20\xa5\xee\x56\x08\x85\xbe\xbb\xe3\x56\xb5\xf1\x33\x2f\x6f\x38\xd2\xbf\x1e\x7c\xf9\x46\x8c\xce\xae\xdb\x50\x39\x6f\xbf\x78\xc3\x32\x2f\x6a\x1a\x52\x47\x59\xad\xea\xda\xee\xfe\x96\xbc\x44\x7c\x1c\xa9\x28\xd1\xcc\xa1\xd0\xce\x94\x41\xaa\xa3\x22\x37\xde\x24\x69\x08\xcb\xf0\x31\x75\xb1\x7a\xc8\xdf\xa4\x14\x70\xce\xbf\xea\x28\x7d\x75\xbf\xdf\xe4\xb1\xf2\x27\x49\xfc\x70\x14\x4d\xcc\x64\x3d\x9a\x79\xf4\x32\x84\xfc\x9e\x91\xcf\xf6\xe5\xcf\x75\xfa\x20\xb8\xf3\xca\x1f\xcf\x9b\x27\x14\xfc\xda\x7c\x89\xbb\xf4\xd6\x3b\xd0\x4f\x3c\xe8\xf9\xbe\x9d\x59\x8b\xb8\x79\xb8\x61\x51\x34\xdc\xbf\x61\x71\xcb\xcb\x5a\xbf\xe5\xf7\xf3\x05\xff\x9a\xb9\x79\xc9\xf5\xad\x53\xb4\xf3\xfd\x91\x92\xe8\xa0\xa7\x44\x2f\x90\x63\x3c\xd8\xf2\xfd\x4a\x68\x39\xba\xb9\xd8\x01\xfc\x2a\xb1\x82\xcc\x52\x5a\xba\xd9\xdd\x39\x76\x79\xc5\x4f\x9f\x23\xe9\xa1\x0d\x56\xf8\x3c\xba\x7d\xe6\x48\x9e\xad\x68\x1d\xec\xd2\xf3\x02\xde\xbc\xae\xdc\xdc\xec\xf8\x7e\x75\xf6\xf2\x7f\x6e\xd8\xdd\x86\x6d\xd0\xe9\x4d\x11\x2e\x5b\x6e\x07\x4a\x2d\x6f\x97\x7d\xbe\x1d\xf6\xf4\x04\xe7\xbd\x7c\xae\x1c\xdf\x32\x4c\x9e\x6e\x7f\x29\xe5\xb7\xaa\xaa\xe8\xc1\x53\x1f\x05\xe7\x14\xa1\x45\xea\x45\xac\xbf\x8d\x6f\x74\xaf\x5c\xc9\x30\xdf\xa8\x87\x46\x22\xf2\xfb\xfa\xfd\x48\xde\xc0\xbd\x0b\xe2\x83\xd1\x50\xad\x8a\xbc\xc0\x22\x46\x7e\xf8\xd1\x7f\x2d\x2a\xbd\x3f\xcc\xdf\xbe\x69\xfb\x92\x57\x07\x2c\x45\x4f\x39\x48\x9d\x08\xdf\xff\x2e\x99\x29\x11\xa4\x34\xde\x26\x11\x50\x64\x1e\xab\x0a\x80\x89\x96\x1d\x8b\xee\x09\xe5\x19\x80\xa3\x3d\xc4\x52\x3e\x9c\x21\xbf\x56\x28\x2a\x62\x72\x8a\xe2\xcd\x8d\x47\x35\x57\x12\xfb\x55\xbd\x38\x00\x9f\xc2\x27\x1b\xcd\x7c\x10\xc9\x3b\x94\xf9\x20\x41\xfe\xa0\xe6\x9a\x5d\x71\xa4\x22\xfc\xbb\x01\xad\xe8\xd8\xd6\x99\xf6\xa9\x7b\x41\xb2\x46\xa3\x93\x7a\x65\x55\x2c\xb7\x23\x2d\x45\x7c\x4d\xa0\xf4\x28\xcb\x4c\xd3\x24\x4d\xb9\x7a\x53\xc9\xb2\xa6\x06\x46\xc5\x4c\xd7\x65\x45\x39\xe6\x5d\x56\xc0\x86\xb6\xa6\x75\xd9\x13\xd7\xa6\x75\xc9\xf5\xf7\xd4\xba\xcd\x1e\x6a\xc1\x2b\xfa\xee\x27\xa9\x5a\xcc\x4a\xe2\x78\x9d\x80\xc8\xf9\x32\x74\x1a\x9f\x83\x39\x19\x27\x99\x5c\x04\x6f\x34\xd2\xbd\x1b\x9e\x2b\xd5\xaf\xcf\x40\xb9\x04\x68\x6d\x05\x22\x31\xb4\xfa\x90\xfb\xd4\x3c\xbb\x70\xe3\x1a\x5f\xf1\x00\xe0\xd2\xe0\xbb\xfc\xa7\x88\x51\xe9\x2c\x5a\x02\x68\x3c\x88\xf7\xe0\xfe\x30\x3f\xd8\x1d\x2d\xdc\xb5\x7e\x9c\xb0\xb5\xc8\x2b\x43\x40\xfe\xaf\x10\x75\x95\xe7\xb8\x62\x5a\x7a\x9a\x69\xed\xfd\x6a\xa3\x69\xbe\x91\x51\x4a\x66\x94\x05\x50\xb2\xe7\x66\x88\xf5\x9c\xce\x71\x1e\x83\x94\x1e\x2b\x98\x89\x57\x82\xd2\xdf\xe4\x26\x6a\xd5\x5c\xe7\x74\xa9\xaf\xdb\xdf\x57\x60\xd7\x6d\xa4\x11\x11\xcc\x79\xf7\x0f\x91\x3a\xd1\x8f\xa1\xb6\x36\x39\xf8\xc7\xb5\xbc\x5a\xd2\x46\xb0\xe1\xa2\xa4\x87\xe6\x83\x0d\xba\x19\xb0\xc3\x8c\x81\xf6\xc7\xed\x3e\x31\xb3\x7b\x1b\x73\x33\xc0\x27\x85\x0d\x87\x99\x06\xf8\x76\x9c\xcd\xa2\x9b\x9e\x69\xcb\x8a\x55\x4d\xea\xe9\x6d\x29\xac\xa7\x6a\xc6\x7b\x17\x31\x22\xd7\x32\x1f\x27\xcb\xab\x52\x45\x61\x9d\x34\x60\xb6\xbb\x98\xdc\x57\x6a\xf3\x38\x91\xac\x8e\x6b\x55\x82\x1d\x05\x96\x92\x66\x14\x78\x69\x96\x9d\x45\xbf\x1c\xff\xc8\xd9\xf2\xca\x40\x67\xea\x3a\xb5\xb1\xc5\x4c\x8b\xf6\x1d\x3b\xd4\x5e\x97\x4b\xab\xf7\xf1\x66\xcd\x1c\xb6\x51\xec\x50\xf6\x59\xd1\xba\xa9\x22\x74\x73\xb3\x5c\xbd\xa6\xa7\x23\x47\x98\xb6\xda\x7d\x55\x46\xc3\xb8\xeb\x79\xb6\xd9\xcc\x58\x33\x0a\x1b\x9f\x12\x8c\x4b\xdd\x50\x0c\xc3\x91\xeb\x75\xbe\xd6\x39\xc4\xec\x8b\x65\x02\x1c\xc3\x96\x09\xe1\x8d\x5c\x8d\xdb\x96\xfd\x64\x19\x0b\x07\xe9\x66\xd2\x34\x8d\x8a\x0a\x97\xe9\xc9\xb3\x55\xd0\xcf\x79\x77\xc9\x73\xd7\x3c\x74\x11\xf2\x88\x94\xbf\x53\xd3\x12\xfd\xc4\x6d\x05\x84\x19\xea\x6a\xd9\xa6\x16\x96\xd9\xb2\xb3\x36\x71\xa6\xcb\x56\x97\x1e\xe3\x4d\x4e\xa9\x7b\x0d\x2a\xd4\xc8\xee\xad\xc1\xa4\x73\x7d\x7d\xc1\x78\x61\xf9\x45\xbb\x07\x66\xdb\xb9\xc1\x1b\xb8\x25\x04\xed\x45\xae\x00\xde\x78\x4d\x3e\x9d\xc6\x7a\x86\x1a\x9e\x65\xb6\x16\x51\x80\x6d\x43\x0a\x5e\x16\xfa\x43\x51\x88\x66\xbb\x0d\x3d\x07\x9d\x4a\x30\xed\x07\x1c\x73\x97\x7c\x59\xa6\x69\x91\xc2\x49\x45\x88\x28\x15\x12\xbb\x58\x43\xe6\xf2\xa5\xb3\x55\x77\x93\x4a\x54\x2a\xe2\xd1\x5f\xc8\x36\x08\xe0\x3a\x4f\x88\x24\xe1\xfc\x0e\x67\xc6\xb7\xd4\xcb\xe6\xef\xd0\x29\xf6\xb1\xc2\xbc\x2a\x3c\x79\xa7\xf8\x20\x2e\xc9\x13\xdd\x05\x9a\xe8\xc8\x6e\x52\x26\x07\x67\xf4\x92\x48\xdb\x6a\xd1\x7e\xe2\x2f\x1c\xd8\x02\x5d\x76\x78\xfc\x1b\x98\xaa\xd6\x2e\xa3\xc9\xe0\x20\x10\xe6\xc4\xfa\x1c\x3d\x8e\x85\x4b\x3e\x05\xf0\x2a\xe9\x14\xe4\x4f\x6e\xb5\x9e\xa6\xb9\x3f\x53\x68\x88\xe2\x52\x42\x8d\x72\xd7\xaf\x7d\x12\x8f\xd0\x1c\xd1\x5e\x37\xce\x27\x7c\x68\x78\x6d\x3d\x99\x30\x11\x50\x7e\x16\xda\xcc\x19\x27\xd5\x66\x37\xda\x03\x92\x6e\x35\xd6\xc7\xce\xa6\x5d\xfe\xf3\x44\x22\x47\x0b\x31\xc6\xcf\x0b\x69\xdc\xf5\x9f\x25\x6e\x72\x10\xcc\xec\x1d\x85\x22\x34\x07\x97\x5a\x07\x81\x0c\x54\x1e\x5d\xb4\x69\xbb\xef\x4a\xa4\x9b\xd7\x16\xb9\xc3\xba\x54\xf0\x44\x3f\x5a\x65\xda\x0f\xa8\xfa\x51\x05\x7d\xf8\x5a\xe9\xb7\x17\x9b\xcc\x50\xa7\x9a\x70\x78\xd2\x98\x7d\x32\x49\x89\x0e\x29\x30\xa6\xa3\xc7\x57\x83\xda\x1d\xad\x25\xd3\xdc\xe1\x38\xb2\x32\xec\x08\xde\xc2\x8c\xd4\x56\xd3\x52\x68\x2a\x95\x26\x8a\x45\x68\x8f\xac\xaa\x0c\x0f\xb6\x0f\xb0\x62\x04\xbe\xf6\x63\xf2\x80\x0a\x41\x9f\x3f\xdc\x6d\xd6\xf1\x4c\x18\xd3\x76\x90\x04\xd1\xc8\x72\x14\x48\x83\x9e\x2b\xf8\x76\xa7\x35\xc2\xf1\xd5\xa0\x97\x64\x46\x59\xb3\x6a\x74\x25\x41\xbf\x5a\xc9\xcb\xcc\xcb\x75\x1f\x0c\x5a\x18\x89\xd8\x66\x0d\x44\x70\x88\x92\x14\x06\xb2\x5e\x01\x80\x21\xe1\x68\x0e\x3a\x21\x39\xaa\x31\x9d\x99\x96\xee\xd3\xcf\xf2\xcc\xc6\x25\xe8\x37\x61\x23\x22\x2c\xfa\xc0\x5a\xd1\x50\x0b\x25\x0c\x70\xbe\x3a\x78\xbb\x37\x38\x0c\x24\x0b\x46\x52\x6e\x34\xd1\xb0\xf2\xf9\x4a\x9c\x73\xf3\x21\x23\xe5\xa4\xa0\x5b\x5b\x14\xfb\x34\x06\x56\x57\xe3\x10\xa3\x93\xa1\x4a\x84\xa5\x44\x56\x2f\x94\x7f\x8d\x40\x4d\xd8\xae\xae\x35\x2f\xab\xd2\xc8\xdf\x90\x58\x28\x0a\x74\xd4\x59\x7a\x31\x92\xa8\xd6\x7d\x49\x4b\xde\xa9\xb2\x25\x6e\x7e\xe6\x25\xb0\xd2\x0a\xf1\x62\x3f\xf9\xf9\x52\x8e\x77\x93\x3a\x6a\xba\x46\x89\x6d\xc8\x12\xb0\xf3\x39\xa9\x35\x09\x54\x82\x64\x86\xb1\xb4\xf6\x11\xc6\x78\x01\x67\x6e\x9b\x35\x51\xde\x15\x89\x87\xf0\x16\x1e\x1c\x66\xed\xdd\xa7\x6b\x1e\xff\x28\x99\x9d\x39\x90\x50\x66\xb8\x12\x32\x69\x36\xe3\x79\x64\x70\x05\x08\x56\x23\xac\x91\x35\xea\x99\x61\x9c\xf5\x98\x85\x2e\x6a\xda\x02\x2f\x6b\xe3\x3d\x6d\x57\xf7\x89\x16\x6c\x4b\xbd\x4f\x32\x17\xe3\xfe\xac\xa9\xa0\x5c\x55\x9b\x7b\xb1\xe0\x70\x90\xb3\x93\x7f\x08\xca\x2e\xcd\x53\x69\xbc\x17\xe2\xd1\xad\xce\x75\xc2\xd7\xf3\x5b\xcc\x7d\xc0\x72\xf2\x2f\x6e\x17\x5b\x0b\xd4\x82\x7e\x10\xc4\xe3\x82\x31\xf9\x53\xd6\xfa\x57\xd3\x18\xfe\x79\x65\x66\x79\x94\x16\x58\x37\x81\x29\xe1\xf0\xa4\x0b\x40\xcb\x06\xd8\x9f\x5e\x33\x0e\x47\x86\x87\x8a\xb5\x89\xd0\x50\x31\x33\x0a\x7e\xd9\x6b\x49\x2b\xc0\x31\xad\x7e\xb3\xc2\x10\xe4\x2a\xb8\xb6\x35\x68\x89\xab\x8b\xbe\xea\x11\x39\x87\xd2\x4d\x17\x8d\x2c\xb1\x7b\xdc\xef\xac\xe5\x53\xc1\xf1\x8a\xe1\x98\x94\xff\x1e\x07\x2d\x61\x8f\xa2\x04\x08\x9c\x9c\xb7\x72\x6d\xc6\x75\x19\x22\x88\xad\x1e\x5a\xc6\x16\xba\x60\x70\x5e\x9b\x2a\xc5\x97\x75\x9a\x45\x8a\x02\x78\xec\xbb\x32\xe7\x4c\x19\x35\x84\x44\xe1\xfc\x21\xb6\x86\x61\x97\x74\x6f\xad\xf2\x91\x60\x35\x54\xe0\x17\xe7\x4c\xd5\x30\xfe\x80\x8c\x5f\x6b\x05\x99\x53\x2f\xfd\x1d\x91\x63\xb1\x45\xe8\xa3\x50\xc6\x06\xf8\x16\x30\xdd\xa6\x53\xc7\x0f\xef\x21\xf8\x80\x50\xac\xfb\x47\xb6\xf6\xe5\xac\x86\x92\x0a\x41\x5c\x50\x0a\x12\xd0\x5d\xd5\xfd\xf2\x89\x44\x91\x0b\xc8\x6c\xf5\x4c\xf6\x58\xa8\x22\x23\xcf\x2c\x3a\x5d\x40\xb9\x14\x34\x0a\xe2\x72\x26\x43\xd1\x6a\x3e\x82\x73\x8d\x91\xa2\x54\xd4\xbb\x2a\xd7\x39\xa9\xc9\x86\x8e\x2c\xfc\xb0\xe4\xfe\x9e\xb5\xbd\xe5\xe4\x01\xd1\xe1\xda\x7d\x49\x49\x0e\x03\xb1\x2d\x03\x81\x76\xeb\x6a\xd8\x0c\xa8\x27\xb1\x64\x45\x58\x04\x61\x4a\x0d\xc6\xd3\x8a\xa7\xa5\x18\x0f\x74\x70\xe7\xdf\x07\xa5\x18\x53\x76\x95\xcc\x4c\x8e\x6b\x45\x08\x95\x16\x91\xf5\x7d\xe3\x04\xc0\xd8\xab\x45\xb0\xca\x4a\x2b\xd5\xcc\x52\xad\x2c\x88\xb0\x61\x1c\x46\x00\xb3\xaf\xcb\xd0\x89\x25\x57\xcc\xcd\x14\x12\x61\x2d\x37\x43\x48\xf0\x4a\x02\x7f\xf0\x4a\xe1\x2b\xaf\x37\x00\x67\x3e\x94\xf5\x76\x17\x8a\x5b\x7f\xe6\xf3\x37\x6b\x08\x44\xca\xd1\x2f\x0d\xf6\xe8\x33\x1e\x65\xc6\x03\xea\x6d\x2b\xc1\x48\x68\x48\x10\x2d\x12\xe1\xff\x11\xec\x62\xa0\x85\xed\x3d\xd1\x3c\x68\xa8\xa2\x5a\x59\x08\xd4\x27\x24\xa7\x33\xce\x39\xe0\x6e\xa9\xb6\x2a\xc2\x4b\xee\x3b\x51\xec\xeb\x58\x43\xd3\x31\xd3\x94\x26\x9a\x24\x90\x49\xc4\x45\x08\x87\xa3\x79\xa2\xc3\xca\xf4\xa1\xc2\x0a\x88\x68\xb0\x59\x92\xcd\xb6\xdd\x02\x6a\x09\x9f\xfa\xc6\x2b\xb6\xe5\x16\x98\x28\x55\xd6\xab\x2a\xdf\x18\xcf\x25\xe2\x40\x6c\x9c\x17\x6d\x32\x88\x6f\xc9\x55\x45\x87\x36\x5b\xdd\x52\x38\x40\xa5\x4d\x90\x68\xba\x90\xd8\x3b\x22\xcd\x2d\x68\x12\x69\xbb\x0f\x11\xd1\xe5\x37\xe6\xde\x1d\xa0\x8d\x29\x4e\xd0\x1c\xb4\x37\x1e\xa5\xb6\x79\xe3\xa9\xc3\x6e\x55\x45\x19\x1e\x7f\x4b\xac\x71\x4d\xd1\xb8\x4f\x40\x88\x37\x93\x86\x60\x94\x83\x43\x56\x56\x9c\xf7\x49\xf6\x5f\x9b\xbe\xb5\xd9\xe5\x61\x6a\x8c\xd4\x43\xbe\x2c\x7c\x95\xb0\xa0\xd3\x88\xc7\x8c\x9d\xbe\x96\x92\xbb\x4a\x75\x17\xad\xc1\x49\x0a\xcf\xc2\xa0\xe0\x3f\xd9\xed\x1a\x2a\x1b\xdd\xda\x10\x24\x83\xa1\xcb\x6a\x17\xad\xe6\x0e\xc2\x49\xa8\x61\x25\x08\x1d\xa2\x04\x39\x08\x9a\xd0\xfc\x29\x61\x7c\xca\xd1\x9b\xb5\x66\x40\xf7\x79\xd7\x89\x07\x66\x8b\x49\x17\x4b\xc2\x3e\xe6\x98\x33\x71\x80\x65\xce\x76\x97\x5b\x4d\xa6\xd1\xcf\x7a\xc2\x34\x01\x84\x9b\x87\x02\x74\xde\xa1\x76\x10\x1e\x52\xcb\x45\xbd\xd1\x85\xe4\xf4\xdf\xe9\x70\x26\xa0\xf9\x9c\x02\x88\x5e\x65\xf3\xca\x7f\xce\x88\x46\xb5\x22\xc9\x28\xef\x60\xa6\x42\x2c\x78\x59\xdb\xcc\xae\xac\x8a\xc1\x4e\x41\x89\xcd\xa1\x85\xdc\x69\x7c\xa3\x78\xc0\x68\x27\x81\x7b\x08\x33\x51\x66\xa4\x4d\xa0\x07\x2f\x61\x36\x98\xb0\x94\x44\xd2\xeb\x69\xe8\x4a\x6a\xfe\x9b\xc2\xf4\x3b\x00\x6c\x4b\x6c\x6c\x3c\xfd\x21\x84\xf7\x5d\xce\xeb\x00\xae\xbe\x14\x12\x05\x28\xfc\x02\x2d\xd2\xc5\x5b\xb2\x6c\x7f\x9c\xa2\xb3\x62\xd8\x7d\x44\x5d\xff\xd6\x61\x55\x73\x86\xb3\xc7\x70\xe8\xfc\x45\xc4\x64\xfc\x26\xfe\x02\x47\x16\xc7\xed\x80\xea\xea\xf9\x72\xe5\x4d\x01\x0d\x76\x09\xaa\x84\x91\x16\x4e\x56\xcf\x51\x19\x5f\xb8\xf5\x02\xfe\x0d\xa5\x0d\xb6\x73\x90\x33\xf1\xfe\x59\x37\x49\x1a\xa3\x79\x9d\xba\x39\x49\x07\xb6\x7a\x90\xae\xbb\x10\x50\xc2\x37\x51\x98\xf2\x88\x91\xfe\x41\x15\x18\xef\x1c\x3c\x53\x72\xc9\xad\x39\xca\xdd\x5b\xae\x0e\x44\x3c\x1c\x77\xb9\x70\x86\xc4\x2a\xd0\x8b\x45\x90\xec\x99\x40\x10\x47\x8f\xbf\xb3\x8b\x04\x29\x15\xb2\x5a\xb2\x9d\x29\x6f\x8c\x59\xd8\xc7\xce\x4a\x0a\xed\x23\x62\x75\xc4\x45\xc7\x0f\x98\x87\x78\x23\xa0\xc4\xec\x5d\x8e\x42\x3a\xd2\xcf\x92\xbc\x26\x82\xbe\x8a\xc2\x8d\xd5\x3d\x65\xd0\x6e\x0b\xd4\x89\x3d\x54\xad\xa4\x60\xce\x18\x4d\x91\xf6\x5c\xc4\xf2\xce\x14\xba\xd2\xeb\xc4\xa6\x85\xdf\x43\x47\xc9\xb0\x0f\x8b\xa2\x1f\xc7\xe1\x12\x01\x0b\x80\x30\xb0\x38\xff\xf5\x59\x64\xbf\x51\xd4\x37\x96\xd0\xb6\x2d\x6c\x82\x82\xb0\x57\x74\xf4\x61\xa6\x96\x1d\x37\xd5\x6d\x56\x16\x53\x2c\xed\xfe\xf9\x0c\xbd\x78\xfd\xa2\x76\x62\xa7\x25\x26\x8c\x40\x79\xd0\x03\x8c\xdb\x4a\xb8\x9f\x33\xf6\x5f\x48\x7d\xa0\xa4\x86\xba\x8a\xc4\xc5\x35\x95\xde\xa8\x48\x30\xc7\x3c\x92\xf0\xd8\xb4\x97\x93\x94\x1a\x8b\x7c\xc6\x8c\x7e\xb7\x43\xfe\xdc\xf6\x41\xf7\xb5\xa1\x39\x89\xb6\x21\xa7\x84\x38\x06\x33\x9f\xe0\x01\x5d\x62\x1c\x09\x17\x86\xeb\xe0\x2d\x15\xfa\x73\x13\xe1\x01\x99\xd9\x7a\x7d\xde\xd9\x09\x78\xba\xeb\xe4\xe4\x19\x65\x4a\xe9\xea\xfc\xc5\x28\x3e\x0e\xd4\xb1\xe0\x40\xb3\x7a\xdc\xc7\x33\x68\x37\xa7\x8c\x76\x90\x20\xc1\xef\x1e\x59\x27\x87\xc8\xeb\x3e\x63\x0f\xa2\xc5\xbd\x64\x4a\x8d\xc2\xbf\x16\x28\x9d\xd5\xfc\x1c\xc1\x18\x34\xe4\x13\x1e\x92\xd6\x87\x41\x73\xeb\x0d\xd2\xea\xbb\xd1\xc0\x61\x99\xd8\x6b\x21\x46\x9b\x4d\xb8\xe3\xe3\x51\xb9\xcc\xe2\x03\x22\x72\x4e\xd5\xe4\x05\x11\xd2\x7c\x30\xc6\x9d\x48\xfe\xca\xe8\x74\x06\x5b\x81\xb5\xfa\xfb\xb2\xa3\xe2\x6f\xfc\xe2\x6a\x73\xf9\xfe\xde\x4f\x34\x34\xf8\xe8\x22\x63\x73\x4b\x81\x4c\xcb\x60\xad\xe0\x73\x19\x24\x8f\x86\xab\xbd\x97\x58\xc4\xbc\xd1\x78\x09\x10\xb7\x28\xdd\x1d\x7b\xa3\xe4\xb7\x21\xe8\x5d\x0d\xc5\x83\x5b\xed\xa4\x70\xec\x57\xc3\xc1\x71\xa4\xfd\x7f\x52\x48\x17\xd9\xee\x76\xd1\xa8\xd7\x01\xf4\x3a\x86\x0e\xe6\xc8\xf0\xed\x99\x46\x9d\x03\x04\x90\xc3\x4a\x1c\xe3\xf2\x3a\xfc\x09\x0d\xf1\x88\x13\x16\x28\xc8\xa3\x4e\x8d\xac\xe0\x10\x62\xa2\x83\x1b\x48\x71\xda\x24\x85\xfb\x0d\x00\xf3\xc1\x90\x20\x53\x81\xa5\xc2\xad\xdf\xd1\xb2\xde\x34\xf1\x85\xb4\x7f\x00\xf5\xe9\x3c\xb3\xa3\xde\xb1\x97\x5f\xa5\x3c\xc0\x2b\xc1\x12\x57\x51\x66\x38\x67\x8a\xb1\x50\x1b\x24\x64\xe1\x77\x0c\xcf\x61\x98\x1e\xff\xf9\x08\xdd\xfb\xbf\x60\x78\x4a\x26\x2a\x86\x88\xf5\xe0\xe4\xe1\x62\xa0\x56\x93\xf6\x1b\x93\x52\xa0\x31\xa2\xa4\x33\x4b\xb5\x4b\xc8\xac\x3a\xd3\x89\xf3\x8a\xfa\x8a\x1d\xc8\x70\x4b\x08\x31\x8b\xe0\xa8\xe0\x95\x53\x76\xf4\x35\x29\xdf\x7b\xdc\x30\xfb\xf9\x8c\x19\xfa\xb6\xcc\x73\x70\x61\xdd\x0e\x83\xc2\x3a\x71\xe7\x5b\x85\xa6\xb6\xa2\x35\x82\xac\xbf\x12\xdf\x4b\x53\x12\xe3\x6e\xcf\x96\xa6\x04\xe5\x51\xe8\x5d\x68\xc3\x5c\xe0\xad\x41\xeb\x34\xc6\x1b\x2f\xe3\x79\x4f\xd8\x7c\x0b\xdd\xeb\x3f\x89\x2b\x51\x06\xb1\xa8\x6b\xfc\xcf\x6e\xf6\x91\x2b\x54\xc2\x35\x2e\x15\xc8\xe6\xc9\xb6\xc9\x18\x25\x3d\xec\x40\x4b\xcf\xad\xe7\xcf\x62\x32\x85\xce\xd4\x9d\x97\xf4\xd0\x33\xea\x22\xd3\x6f\x23\x83\x8b\x29\xa0\xfa\xdd\x70\xf4\xdf\x49\x5c\xb2\xc9\x14\x92\x89\xa4\x4f\x8d\xad\xf1\x40\x82\xda\x85\xa5\x3d\xd6\xf5\xc1\x99\xda\x89\x99\xb3\x21\xf5\xcb\x51\x06\xa4\xcb\xa1\x35\xee\xea\x34\x29\x0c\x5b\x0d\x77\xfa\x60\xb5\xfc\x4b\x2f\xfd\xcd\x93\x44\x20\xa9\x1a\x83\x1e\x2f\x0a\x93\x77\x7c\x31\x51\xf3\x0d\x04\x07\x9c\x4a\x57\xe1\xdd\xc7\x17\xf7\x95\xc9\x16\x3f\xee\x20\x7a\xd2\xcc\x48\xe9\x79\x6b\x08\x4e\x23\x75\x14\xdb\xc7\x74\x7a\x15\x02\xfe\xe2\xf3\x5d\x03\x06\xc3\x85\xe3\x3e\x2b\x5d\x95\x8f\x65\x3f\xb1\xff\xda\x3b\xde\x99\x7c\xc4\x8a\x84\x5a\x29\x8b\x32\x2b\x24\x88\x9e\xfc\xcb\xf0\xe1\xf0\xac\x61\xe3\x6f\x0e\x2a\xf4\xf6\x73\x52\xbf\x97\xfe\x8d\x4b\xcc\x80\x33\x7a\x53\x3c\xd5\x55\x0a\xe2\x53\x02\x11\x80\xb8\x14\x6a\x21\x2e\x3d\xcb\x84\x9b\xbb\xdc\x0c\x1f\xe8\xd8\x1f\xa1\xbb\xf3\x4b\xd9\xcd\x38\x63\x09\xae\x59\x29\x81\x62\x24\xd7\x21\x82\x0c\x24\xfb\x97\x11\xf4\x15\x05\x22\x2d\x68\x6c\x7c\x8b\x46\x88\x96\x68\xcc\x26\x02\xfc\xd5\xd3\x5e\x15\xb4\x60\x2a\xcb\x4e\x2c\x51\x06\xe6\xf7\x39\xc8\xc0\x12\x29\x62\xf1\x27\xff\xd5\x47\x49\xec\x04\x3d\xa2\x45\x5c\xda\xcb\x3f\x8b\x7c\x1d\x55\x04\xbd\x79\x3c\x2e\x89\x3d\x7b\xfd\xc0\x6a\xd0\x9e\x0c\x99\x07\x28\xa2\x70\xd6\xdc\x72\xf9\x64\xcb\x11\x79\xa6\x22\xc9\x09\x45\x2c\x15\x69\x8e\x45\xed\xfc\x68\x40\x1e\x48\xf5\xae\x5e\x9a\x0e\x2d\x58\x3a\xc4\x2f\x95\x98\x9c\xb8\xac\x54\x33\xe4\x72\xaa\xcc\x50\x6d\x85\x47\x37\x4e\xb1\xae\x70\x48\xb2\x91\xa6\xe4\x21\x91\x6a\x08\x0e\x1a\xca\x0d\xc7\x4d\x82\x46\x74\xa5\xbd\xb2\xe2\xf8\x3a\xeb\xb9\x79\x02\x14\x48\x6c\xd1\x18\x4d\xb8\x75\x35\xc7\xc6\x13\x87\x61\x39\x54\x80\xad\x03\xcc\x61\x4a\x3c\xf5\xee\x71\x28\x67\xf7\x08\x9c\xf6\xa4\x63\x0b\xf1\xb1\x26\x75\x21\xc4\x99\x5d\xfa\x62\x07\xa8\x4b\xfc\x22\x89\xfa\x86\x4c\x3d\xc6\x13\x15\x6c\x56\xcb\x8a\xc0\xa3\x62\xd5\xe9\xef\xab\x05\x62\x70\x2c\xdb\x08\x73\x54\x34\xae\x59\xcf\x72\x87\x68\x9b\x84\x56\xed\xf5\xea\xb5\x0d\x9f\x5f\x53\x08\xf0\xae\x7d\xdd\xa7\x63\x88\x8b\x30\x66\x06\xaf\x7c\x6f\xab\x80\xe9\x64\xec\xcc\xf8\x59\x0c\x22\xc2\x31\x0d\xa9\xa5\x22\x35\x65\x22\x28\xd6\x0a\xb0\xbc\x7e\x59\xc6\x87\x40\x14\x20\x6c\x27\xa9\x95\x87\x21\x80\x08\x47\x68\xe1\x99\xea\x9d\x42\x22\x6f\x34\x7a\x5e\x11\xaa\x28\xb7\xb9\x4e\xa4\x3a\x9f\xef\x52\xd3\x61\x1d\xae\xd8\x93\xec\x71\x74\x5a\x66\xdd\x5d\x6c\xa7\xe0\x8f\x0b\x29\xeb\x0f\xd1\xcf\x1e\x69\x1c\x00\x0c\x07\xa4\x63\x85\xb9\x27\x84\x0f\x16\xd7\x2a\x7c\xf9\x74\x10\xd8\xcb\x51\x02\xdc\x8b\xbd\xa2\x36\x62\xf4\xe3\x7f\xd1\x8e\x3d\x85\x5a\x9f\x00\x30\xf0\xc0\xbb\x16\xce\xab\x61\x46\x20\x70\x5d\x90\x7e\x98\x3d\x4e\x6d\x5c\x39\x46\xc3\xfd\x19\xa8\x15\xce\x0a\x04\x86\xf8\x48\x70\xc6\x2e\xe6\x8e\xe8\x06\x3e\x42\xec\xb5\xd4\xc0\x54\x17\xfa\x91\x3e\x07\x41\x2f\x5c\x34\x8e\xaf\xb7\xf3\x2e\x45\x64\x71\xa4\x14\xa5\xd6\x84\x2a\x40\xaf\x6b\x55\x27\x34\x41\xae\xd5\x79\xde\x22\xed\xd8\xba\x06\xc1\x7f\xa2\x9a\xc3\xdf\x29\x81\x30\x0b\x13\x82\x96\x2a\xd9\x8c\x25\xd8\xa9\xd9\xd2\x2d\x6c\x4a\x28\x39\x0b\x01\xf0\x83\xad\x03\x1d\x3a\xe8\xbc\x03\x29\x17\x17\x49\x05\x43\xc3\xb8\x08\x1c\xa0\x0f\x99\xd1\x3b\x30\xde\x03\xb9\x3a\x58\x83\x4b\x4f\xe7\x63\x0c\x66\xaf\xdb\x09\x88\xff\xb4\xf9\x33\x70\x63\xe4\x31\x9b\x90\x37\x3a\x96\x5d\xb1\x4b\xa1\x9f\xc6\x43\x1d\xc3\x7e\xe9\xf6\xb8\x2d\xd7\x5f\xf0\x2b\x00\x99\x27\xc2\x59\xc3\x73\x86\xfb\x8d\x77\x93\x6e\x3f\x5d\xce\xb9\x20\x9b\xbb\xfb\xc8\x66\x34\x89\x6f\x28\x35\xa8\x61\xbd\xe9\x5c\x82\x2a\x85\xea\x85\x85\x15\x0c\xbd\x44\x74\x9d\xdc\x37\x48\x15\xe5\x9f\x81\x46\x7e\xb4\xb3\xb5\xec\x0d\x7b\xf0\x7e\x06\x70\x81\xe0\xfa\x76\xa4\x5a\x5d\xc0\x72\xa4\x68\xc8\xca\x56\xcb\x1d\xae\xbd\xbd\x84\xe6\x66\x14\x51\x33\x41\x2f\x70\xe7\xd4\xee\x20\x9d\xc4\x38\xc9\x88\x10\x82\x28\x57\x8e\xba\x15\xb2\xb2\x56\x29\x0b\x34\x98\x8a\x83\x46\x6a\x13\xd6\xca\xcd\x59\x7f\x1d\xc9\xd0\x34\xe2\x32\x4e\x6c\x3b\x43\x25\x8a\x87\x7d\x93\x83\x9f\xba\xd5\xba\x0a\xba\xb9\x78\xe7\x24\x02\x81\x59\x5b\x74\x4b\x8b\x90\x6b\xf9\xf5\x72\xc8\x35\x59\x4e\xe8\x6b\x85\xe1\x55\xd6\x2b\x82\x96\x16\x02\xc4\x18\xca\xff\x0e\x92\xbe\x1b\xe8\x5d\xe6\x3b\xb2\xd3\xb2\x5e\xf5\xa3\x38\x4a\xc1\x62\xc5\x60\xd0\xdb\x4e\x97\xb4\x9e\x58\x47\x02\xf7\xc2\x88\xe6\xf9\x9a\x12\x02\x42\x8f\x57\x0b\xff\xe8\x54\x08\x3c\xa5\xea\x05\xa4\xfa\xc8\xaf\xe5\xda\x37\x37\x36\x74\x01\x07\xad\x6d\x4f\xd8\x30\x4b\x5b\xec\xaa\x60\xf6\xbf\x0e\x05\xad\x25\x3f\xeb\xeb\xf1\xe2\x5d\x93\xfc\x4f\x91\x12\x64\x3a\xd5\xca\x7d\x48\x86\xb6\x0a\x08\x61\x4f\xe6\x59\xab\x9f\x14\xca\xdb\xf5\x99\x45\xd8\x7f\x01\xfd\x63\xc7\xeb\x27\xb0\xcc\x49\x73\x07\x8d\x77\x49\x20\x26\xcf\xe1\x22\x29\x43\xa4\x90\xe9\xbd\xfd\xfa\xbf\xf1\x8b\xcb\x08\xc0\xf5\x40\x71\x17\xdb\x96\x35\x68\x53\x2b\x0c\xcb\xc2\xc3\x03\x07\xa5\xc8\x09\x4b\xa0\xc7\xbf\x2e\x92\xc8\x5e\x38\x66\x52\x8d\x1f\x1f\xed\xab\xcb\x37\xe8\xb0\x35\x3b\xd6\xfd\x04\x17\x8b\xa6\x9b\x8e\xc4\xcf\xc4\xff\x57\x92\x6c\xde\x70\x01\x47\xa6\x02\x95\x02\xa1\x97\x12\xfc\x24\xfa\x01\xb2\xa9\x1c\x79\x59\x2e\x60\xe8\xdc\x48\x33\xc1\x3b\x47\x61\xc6\xc2\xa7\x80\x0e\x70\xa9\x5e\x71\xf8\x23\x1f\x6b\x94\xb9\xda\xc4\x2f\xc3\xd6\x01\x78\xbb\xa7\x58\x12\x63\x66\x4b\xc4\x12\x40\x24\xc0\x91\xd4\x36\x76\x6f\xad\xe7\x8a\x20\x97\x5f\x79\x10\x94\xac\xc1\xc8\x02\x13\x0f\x98\x55\x5b\xc8\x68\x4e\x49\xfa\x1c\x86\xf1\x06\xae\x09\xff\x5c\x0e\xb0\xe3\x61\x65\x26\x65\xe5\x9c\xc8\x00\x4c\x0f\xc5\x05\x62\x5d\x3b\xae\x17\x0b\x9f\x75\xc6\x1d\x84\xb3\xac\x1b\x80\x55\x18\x44\x06\x24\xc2\xc1\xdd\xd7\xb5\x15\xf9\xd1\x73\xa4\xeb\x87\xc1\x18\x66\xb3\x0b\xbc\x8c\x90\xa3\x70\xf1\x11\xad\x2b\xb5\x05\x21\x17\xa3\xb1\x7b\x40\xd6\xc8\xd0\x6b\x2d\x9d\xca\xab\x18\x6f\x10\x73\x2e\x35\x1c\x1d\x0d\x6a\x16\x58\xf1\x8f\x4e\xda\x81\x00\xaf\x64\xf9\x5a\xf9\x15\xed\xa3\x0f\x43\x31\xfb\x18\x0b\xcc\xbf\xb3\xc4\xa7\x78\x32\x76\x68\xc1\xc4\x02\x11\x28\xee\x19\xe5\x61\x57\xfd\x5d\x3e\xc5\x3c\x16\xf9\xbc\x4f\x8f\x60\xde\xc5\x9b\xcd\xe2\xf0\x1c\x0c\xbf\x06\x71\x78\x83\x2c\x7c\xa5\xe8\x2a\x89\xb0\xb9\x05\xc6\x9b\x07\x2b\xd5\xbb\x40\xba\xc8\x61\xbc\x7d\x79\x24\xe6\x96\x7f\xd3\xb4\x7e\x84\xe7\x17\x57\x33\xb7\x83\x90\x75\x44\x85\x07\xa2\x9c\xc7\xab\xc3\xe1\xd2\xf7\x23\xf0\x65\xb7\xf9\x77\x48\x14\x32\xd6\x95\xe1\x56\x7f\x91\xc8\x11\xcd\xfe\x0a\xec\xb8\x62\x76\xd9\x34\xa9\x59\xbf\x1f\x97\xc3\xdd\xa1\x86\xa2\xe0\x88\x00\x20\x45\x0c\x5b\x20\xc7\xa7\xe0\xcf\x39\xc9\xcc\xaa\x33\x85\x02\xd7\xff\x84\x34\x63\x5b\x3e\xa3\x2d\xe2\x26\x2d\x08\x33\x6e\x3a\xeb\x1f\xa7\x3e\xd3\x36\x60\x80\x47\x76\x0e\x80\x8e\xb6\x17\x4c\x1d\xec\xf0\xb7\xbd\x85\x81\x0d\x5c\xbe\x8f\x1c\x2c\xae\x90\x79\xaa\xcd\x06\xb3\x50\x4b\xf2\x82\xbc\x51\xc5\xd7\xf7\x81\xf5\xa3\x36\xc0\x4a\x61\xa1\xad\x55\xb1\xdb\x97\x3b\xa4\x1d\x5e\x24\x76\x6f\x21\x57\xed\x1a\x6d\xcc\x85\x92\xda\x76\x59\x6d\x3c\x49\x65\xc9\xfe\x4f\x8c\x64\xd7\x9c\x8f\x2c\xd4\x65\x36\x70\xb7\x0d\x83\x06\xe0\x71\xe4\x02\x4b\x2a\xe1\x5d\x79\x63\xe6\x51\x75\x04\x9b\x08\xe7\x8b\x4c\x2a\xad\x0a\xb4\x6a\x05\x25\xbb\xc5\x35\xd4\x14\x09\x25\xce\x5e\x7e\x02\x88\x06\x4a\xbb\x08\x7a\xab\xc3\x94\xa9\x94\xc5\xaa\x3d\x9d\xff\xf6\x49\x94\x16\x9c\x48\x78\xf3\xa9\xcf\x64\x6c\xef\xea\xf4\xf5\xfd\x92\x41\x0b\x9f\xf7\x4e\x87\xe9\xdb\x34\x8d\x45\xd9\x5f\x7f\x51\x01\x9a\xe7\x7f\xf7\x31\x4f\x0f\x80\x39\x40\x43\xdf\x36\x5e\x69\x7f\x74\x28\x2e\x5b\x18\x4c\x6d\x6c\xcc\x42\x00\xfe\x3b\x46\xda\x72\xc3\x60\x2f\x5c\xdd\x21\x51\x15\x9c\x21\xca\x28\x7f\x6f\x85\xed\x7b\x06\x1f\xc9\x79\x69\x5a\x29\x71\x83\x12\xb4\x1f\xf2\xbf\x1f\x7f\x2f\xc0\xfa\xfd\x94\x62\xc3\xbf\xf4\x0a\x88\x15\x0d\xc0\x50\xd5\x92\x01\x00\x60\x32\xff\x31\x1e\xba\xdb\xd8\x03\x00\x1a\x21\x57\x9a\xb2\xb1\x1b\x3c\x70\x5b\x0f\x68\xbc\x81\x32\x4a\xc5\x2e\x78\x94\xad\xae\x10\x9d\x97\x77\x1f\x12\xe4\x07\x11\x49\xae\xa5\x0f\x3e\x55\x03\x4c\xf9\x9c\xcc\x6f\xaf\xaf\xb4\x60\x05\x79\x3b\x7e\xb3\x1c\xde\x22\xa5\x42\x8e\x29\xd7\x4d\x98\x59\x32\x97\x86\x4b\x29\x51\x0d\xaa\x4e\x56\xad\x63\xe3\xdd\x4f\x13\x47\xf3\x19\x0d\x3b\x32\x46\x65\x9d\x2a\xba\x25\xa7\xe7\xa2\x10\x8d\x4d\x6c\xf3\x6b\x98\x61\x86\xe8\xfa\xce\x55\x96\xaf\x90\xf9\xc0\xe4\xf4\x92\x89\x61\xd1\x5a\xbe\x89\xfd\x26\xc1\xb9\x65\x46\x53\xd4\xb4\x57\x1b\xf5\x0d\x9d\x7d\xec\x10\x88\x7a\xc5\x8b\x7e\xe1\xd4\xbb\x5d\x59\x9e\x8c\x4b\xc6\xd5\xae\xe0\xd0\x1e\x0b\xfb\x8a\xa6\xda\x16\x24\xa8\x8e\xeb\x0e\xf2\x14\x0e\xea\xee\x40\x79\x64\x54\x8d\xa1\xca\xd5\x2c\x91\x86\x85\x7a\xf6\x1e\xc3\xb4\x3b\xab\x40\xe3\x91\x71\x8d\x28\xce\x3b\x1c\xed\x46\xa0\xf7\x3f\x2d\xa1\x2f\xfb\xbb\x29\x5e\x48\xd8\xa4\x92\xc6\xca\xf5\x7e\xb6\x52\x6f\xac\xeb\xa9\xda\x76\x00\xb4\x5b\xe7\x49\x18\x47\x18\x9a\xdd\xd8\xea\x82\x6f\x14\x2d\x17\x38\xea\x70\x27\x02\xd8\x9f\xc3\xfd\x51\x79\x91\x41\xb3\x76\x08\xd8\xbb\xcf\x04\x08\x2a\x22\x55\x09\x70\xed\x09\x09\x36\x11\x20\xca\xcb\x09\x3b\x32\xe8\x32\x7e\x00\xbc\x1a\x69\xfd\x8d\x13\x32\x88\xef\x71\xd6\x70\x2b\xaf\x68\x3b\xe6\xc0\x15\x8c\xba\xe9\xed\xd8\xae\x49\xfb\x07\x32\x0a\xcd\x3d\x09\x00\x02\x6d\xb5\x76\x8f\x07\xfe\x46\x18\xc9\x2a\xc4\x30\x66\x31\xac\xaa\x9e\xdb\xbf\xcc\x6c\xb7\x5f\x55\x3d\xf9\x08\x3e\xf7\x5b\xe6\x95\x4d\x1f\x50\x2b\x6e\x0f\xda\xd9\x6e\xe9\x82\xeb\xf0\xce\x89\x53\xd7\x4f\xbd\x3e\x9c\x00\x0d\x7c\x1a\xcf\xc8\xca\xcd\x2d\x0a\x03\xf5\x6d\xc7\xf6\xe0\xe1\x54\x9f\x35\xc0\x7f\xbb\x98\x4d\x27\x15\xcb\x9b\x1c\x8f\x19\x11\xf4\x39\x11\xe9\xaa\x03\x29\x52\xa4\x46\x2f\x16\x4e\xb6\x02\xb8\x74\xf1\xb9\xac\xb0\xe8\x10\x8b\xda\x19\xc7\x15\xb0\x39\x4f\x19\x30\x8f\xb3\x84\xf8\x1a\x15\x57\xc6\xde\x30\x32\x71\xc7\x15\x8e\x3a\x90\x76\x2c\x57\x9a\x83\xcd\x4c\x37\x35\xdc\x43\xfc\x56\x76\x35\xf0\xf0\xff\x3b\x05\x85\x1b\x8f\xca\x6b\xe4\x07\x9f\x89\xf2\x1b\xa6\x31\xc3\xe3\x83\xfb\xd7\x96\x43\x13\x34\x46\xd3\xe5\x23\xdb\x2e\x73\x16\xdd\x35\x93\xab\x22\x1e\x06\xf5\x08\x70\x5b\xd3\xd8\x84\x61\xbd\x91\x68\x61\x86\xae\x0a\xd2\x5b\xc8\x03\x48\x7c\x44\x67\xf6\x48\x52\xcd\xb6\x7a\x9a\xcc\x62\x85\xd2\xef\x0f\xdb\x43\xe1\xd4\x98\x71\x37\x88\x44\x5a\x4e\x4a\x1c\x78\x9e\x1a\x4a\x37\xcc\x10\x75\x43\x39\x91\xe0\x7b\xd7\xa6\xe7\xcd\x2a\x53\x5f\xed\x67\xf4\xe6\x16\x7a\x16\x72\x14\xae\x84\x3b\x82\xbc\xd9\xf3\x9d\x31\x96\x03\xfc\x52\xa7\xe0\x20\x09\x89\x1d\x22\x40\xc7\xb3\x41\x5e\xeb\x42\x1f\xa6\x0a\xb5\xa0\xea\x8e\xb7\x33\x08\xb0\x9c\xdc\x8a\x6d\x6e\xc3\xb2\x5c\x53\x25\x0e\x7d\x50\xc3\x8f\x6d\x49\x9f\x54\x54\xd4\xd9\x39\x7e\xfd\x60\xdc\x8d\x8e\x61\x4a\x46\x9d\xdf\xd8\x6b\x17\xa4\x7e\x7d\x6c\x87\x22\x85\xf7\x7e\x1e\x6b\x11\x51\xdf\x46\x0c\x60\x94\x7f\xae\x45\x3f\x88\xe7\x0b\x37\x6b\xf0\x29\x5d\x3e\xf5\x03\x3a\xe3\x94\x1a\xac\xe1\x17\x54\x05\x1d\xae\x68\xa5\x6d\xff\x46\x31\xc2\xa8\xa9\xf2\xcf\x19\x30\x98\xa2\x8f\x5a\x7f\x73\x6f\x3e\x92\x1e\x84\x2a\xba\x7a\xb6\xfc\xf7\xa5\xca\x7d\x8f\x15\x8e\xc1\x55\xea\x30\xb3\x5f\xfb\xfa\xde\xe7\x9b\x5c\xf8\xb1\x31\x14\xeb\xe7\x5d\x12\x49\x49\xa8\xff\x88\x5d\x80\x7a\x0a\xce\x1d\x20\x97\xff\x1f\x8e\x6f\xd1\xfc\x34\x3f\xa0\xea\xc6\xb0\x3e\xff\xf5\x41\x2f\xde\x3b\x44\xd6\xb5\xbe\xa9\x13\x7b\x96\x33\x00\x00\xf4\x90\x14\x11\x54\x31\xdf\xbe\xca\x90\x54\xc0\x5d\xc3\xf6\x2f\x73\x1c\xa5\x4e\x29\xb6\x74\x1c\xa3\xe6\x22\xeb\x28\x4e\xfc\x87\x47\x91\x52\xa9\xd2\x61\x5d\xc6\x63\x92\x76\x80\x8d\x18\xc1\xe2\x3e\xcc\x78\x60\x03\x0a\x39\x69\xc8\xf8\xcf\x10\x23\x42\x76\x94\x28\x1e\x29\x0b\x1c\x88\x08\x0a\x6e\x3a\x32\x9a\xbe\xe4\x1f\x33\x49\x13\xa4\x01\xcf\x8c\x42\x14\x0f\xbe\x9e\xa6\xc6\xc0\x60\xd9\xd7\x4e\xae\xa5\x34\x51\x90\x28\xb5\xff\x43\xf2\x75\xf3\xf7\xc7\xe7\x8b\xc1\x4e\xf1\x02\xec\xd6\x2e\x1e\x71\x5b\xf8\xbf\xd6\x77\x15\xd1\xed\x3c\x89\xd0\x76\xd0\x5f\x5a\x63\x37\x53\xe7\xb1\xbd\xf9\x79\x0c\x8c\xbb\x47\x77\xde\xb9\x34\x17\x1e\x7a\xcb\x7a\x24\x2d\x38\x87\xbf\x85\x1f\xad\x46\x21\xd6\xa9\x36\xa4\x5d\xb2\x53\x14\x55\x8a\x65\x5b\xeb\x6b\x4b\xe7\xd1\xf3\xf1\x2d\xdf\xee\x53\x0d\x42\x78\x4f\x28\x50\xa6\x16\xe3\xd4\x93\xc5\x66\x26\xa5\xe4\x65\x2c\x5c\x67\x7e\x27\xc5\xfa\x59\xa5\x28\xbe\xe3\x48\xf5\x3a\xcf\x5a\x9d\xa5\x33\xb0\x16\xd9\x1e\xbc\x0c\x1e\xec\x5d\xcd\xdc\x2c\x1a\x49\xf6\x4f\x62\x57\xe3\xbf\xc5\xa2\xd1\x0c\x27\xa4\x70\x27\x73\x15\x52\x7a\x20\x01\x5c\xee\xde\x93\x3d\x4b\x63\x74\x34\x3a\x25\x87\xf0\xa0\x05\x3d\xc4\x9d\xf5\x0b\x5f\x8d\x97\x15\x74\x45\xd2\xb4\x90\x59\xe2\x99\x43\x9e\x79\xc1\x43\xb1\xcb\x30\x73\xbf\x2e\xc1\x0a\x19\xa6\x91\x0e\xaf\xa7\xe5\x91\x97\x01\x96\x4c\x7d\xaf\x0b\x9a\xbf\xb9\x94\xb2\xd4\xed\xac\x6d\x34\x5d\x8a\x0e\xbe\x9a\x0d\x16\x69\x8d\x7f\xff\x5d\xdd\x55\x58\xeb\xef\x17\x0a\x62\x4b\xdc\xbe\x2e\xe0\xa2\x0b\xdc\xa7\xd9\xc4\x47\xcb\x60\xc8\x0e\xe5\x65\x72\x7d\x95\x71\x30\x7d\xfc\xdb\x63\x26\xf9\xb0\x4d\x94\x2a\xc4\x4e\x2c\x13\x5e\x7d\x28\x26\xb0\x9b\xa6\xef\x93\xd2\x56\xdf\xcb\x93\x70\x8d\x4a\x0c\xea\x9a\x16\x94\x5d\x60\x3a\xe7\x75\xcd\x87\x45\x03\x77\x8e\x86\xbe\x0e\x44\x9a\x1c\xf2\x82\xb3\xa0\x6a\x43\xc1\x22\xed\x2f\x00\x1d\x6b\x34\xbc\x82\xe0\xaf\x16\xf1\x12\x88\xd0\x49\x4e\x43\xc0\x1a\x0b\x6c\x55\x13\x20\x94\xa4\x6f\x02\x1b\xe1\x3c\x40\xbe\x2a\x11\x07\xd2\xc8\x6e\x90\x95\x07\x99\xa1\xe8\x71\x29\xa0\x35\x72\x36\x4f\x81\x54\x7f\xc9\x02\x2a\x50\x71\x53\xed\x74\x32\x78\x03\xfb\x28\xb0\x26\x7d\xf5\xd6\x11\xbe\x7d\x82\xf5\x34\x63\x7a\x42\xda\x61\x54\x78\x04\x66\xd9\x19\x74\xf4\x47\x50\x1b\xfe\xd6\x1b\xb2\x3a\xeb\x12\xac\xca\x0f\x29\xed\x75\x46\xbc\x19\xa4\x64\x91\x57\x56\x76\x2f\xf0\xd0\x75\xf0\xb6\xa7\xfd\x7e\xf8\xe2\x7e\x0f\xa5\x0c\xcf\x6e\x15\x9e\xad\x9c\x96\xb8\x13\xb7\xfb\xb8\x38\x93\x8f\x92\x2d\xad\x04\x37\xeb\xcb\xa7\x8c\xfe\x8d\x69\xc9\xfa\xb5\x72\xac\x7b\x89\x67\xb5\x04\x2d\x99\xd8\x70\x82\x88\x7a\xf8\xfc\x77\xd6\x39\x05\xe3\xd9\x33\x90\xe7\x18\xa5\xd5\x79\x62\xca\x72\x53\xc0\xe1\xf7\x27\x26\xff\xb7\x3b\x8c\x2e\xf0\x5a\xec\xf2\x73\x23\xe6\x6f\x4a\x9a\xb6\xde\xb2\x30\x38\xed\x85\x31\xf2\x43\x7f\x3c\x8e\xed\xd9\x84\xf5\xbc\xb0\x57\xfc\x54\xb6\x21\xbb\x0c\x82\xc3\x61\x0b\x52\xf3\x52\x3e\xfa\xa7\xd1\xa7\xdd\x58\xef\x67\xbf\x9d\x3e\xe8\x06\x7e\xa7\xeb\xe9\x39\x2c\xdc\x64\xf6\x78\xfc\x32\x81\xd0\xe5\xbd\x9a\xab\xe0\x47\xea\x5a\x30\x8e\x65\xde\x8e\x8f\x69\xe3\xd5\x11\xa8\x69\xf1\xe6\x16\x79\x98\xb9\x72\x1a\x70\x7d\xdf\x85\xfc\xbb\xe1\x3b\x2d\xef\xeb\x56\xfc\x25\x1b\x7d\x2c\xf6\xac\xdb\x87\xbe\x24\xc7\xed\x79\x25\x02\xf1\x3c\x87\xc0\xa8\x8b\x97\x5c\x68\xfb\xcb\xf8\x3b\x1a\xbb\x3f\xbb\xb0\x9a\x50\x2a\x9d\x6d\x2d\xfe\xaf\x96\xa5\x44\x4c\x7c\x82\x30\x86\xf9\xa0\x8d\x11\xb5\xb3\x15\x61\x2a\xe1\xbf\xa1\xde\x3b\x12\xe1\x57\xfc\x37\x64\xc5\xee\xfe\x46\x7f\x49\x40\x34\xfc\xde\xe3\x67\x9c\x9c\x0b\x35\x62\xb6\x52\x0c\xef\xf9\x27\x89\x36\x67\x7d\x7d\x2c\x43\x82\xa4\xa7\x1a\x03\x57\x71\x90\x28\x8f\x09\x7a\x1a\x62\x63\xd4\x95\x6a\xf4\xd1\xf2\x18\xcd\xef\xc8\x74\x1b\x46\x6e\x17\x65\x78\x38\xd1\x0e\x36\x96\x7f\xfa\x3c\x1e\xca\x15\x12\x3b\x87\xe9\x8c\x92\x2a\xc8\x2e\x67\xef\xf9\x4d\xb2\x04\xfa\x8b\x62\x30\x82\xd2\x56\xe1\x95\xe4\xad\x51\xe5\x08\x3f\xd7\x03\x34\x72\xe0\xf5\x5f\x7b\xf8\x53\x5a\x7c\xe2\x6b\xf5\x43\x13\xa1\xdb\xd9\x0f\x6a\x09\xde\xc2\x0a\x56\x8c\x69\xbc\x93\x46\x9c\x1c\xe4\x36\x30\x45\xe0\xe4\x41\xab\x4a\x43\xf4\x9e\xf2\xa0\xc4\x9e\x12\x97\x19\xf1\xea\xaf\xd1\xeb\x27\x4f\x20\x74\xf0\xcd\xfe\x73\xea\x35\x9d\xbf\xe6\xf6\xb4\xb6\xdf\xf4\x8a\xe8\x2b\x58\xad\x59\x56\xc8\x25\xa7\x95\x55\xe4\x67\x24\x9a\x93\x04\x59\xf7\xc0\xe8\x3b\xa9\x73\xac\xb8\x55\x28\x66\x60\x95\x68\x5d\xd8\x97\x04\x26\x23\x9c\x06\x62\xbc\x3e\x83\x63\xd4\x95\x5c\xdc\x47\x88\x45\xe8\x36\xd7\x7e\xfd\x62\xa9\x84\x5d\x44\x75\x90\xda\x64\x8f\x38\x26\x0a\x2a\x27\xc9\xed\x38\x36\xa7\xe7\x34\xba\xe8\x3b\x29\xa9\xe2\x12\x23\xbf\xb0\xfd\xcc\x58\x08\xa4\xe9\xd1\xcc\x1a\x37\xde\x98\x12\xf3\xe8\x4b\x6a\x93\xa7\xd2\xd1\x37\x53\xc5\x7e\xf4\x90\x3e\x32\xa0\x39\x11\x8a\x88\x65\x18\x1e\x25\x3a\x37\x6f\x8b\x42\x6c\x8c\x47\xd5\xa6\x5e\xc0\x62\x8b\x62\x33\x78\x59\x02\xb0\xf0\x94\x7d\x1d\x22\xca\xb7\x53\x63\xe8\x22\x14\x21\x04\xec\xa5\x48\xc7\x21\x8c\xe0\x88\xc0\x88\xe2\x4d\x98\x9f\x3c\x80\x75\x98\x9e\x08\x97\x98\xa6\x25\x1c\x0f\x0a\x5c\x80\xda\x82\x3e\x91\x8b\x0d\x52\x8a\x6e\x46\xa2\xfe\x86\xcf\x81\x15\xf8\xdc\x93\x97\xff\x26\x95\x83\x77\x48\x7a\x65\xdc\x57\x10\x85\xde\xc9\x9e\xe9\x5b\x6f\xef\x44\x4e\x6b\xe8\xc9\xf6\xbb\x3f\x6e\x6e\x12\x23\x1f\x73\x20\x99\x3f\x77\xac\xc7\xed\x47\x6e\xb0\xa3\x8f\x93\x3c\x86\x83\xca\xbc\xdf\x9f\xb1\x9b\x46\x1b\xeb\x5f\xf8\x1d\x61\xea\x3f\x00\xba\xbe\xd7\xff\x07\x73\x42\x6f\xa1\x57\x12\x4e\x16\x59\xe2\x4a\x0e\x73\xdd\x4e\xdf\x53\x06\x06\x04\x3e\x84\xc0\xb6\xc8\x0e\x8c\x2a\xd6\x9a\x03\x63\xa2\xfe\x28\x9b\xd6\xb1\x8c\xfb\xfd\xea\x3d\x8b\xc0\xda\xa0\x87\xff\x87\x44\xd7\x74\xc8\x3e\x6e\xaf\x30\xdd\xdf\xc2\x51\x42\x3f\x74\x0d\x0a\xbc\xcf\xb3\xe9\xaf\x0c\x05\xe2\xfb\xc2\x9b\xab\x3f\xc9\xc6\x4b\x26\x42\x9c\x61\x54\x6d\x2e\xea\xaa\x8f\x3d\x04\xe3\xfc\xbf\xa0\xd6\x31\xe2\x7f\x1d\x6a\xfa\x48\x65\xab\x9c\x4b\xc8\xbd\x71\x28\x0e\x97\xcb\x06\x47\xd6\x32\x6f\xdd\xcb\x7f\xd6\xe4\xef\x88\x4e\xac\xa6\xfb\xd7\x6a\x62\x79\xc5\x83\x46\x89\x6d\x7e\xe9\xef\x0d\x0c\x21\x65\x10\xf8\x26\xae\xc8\x2f\x14\x6d\x65\xbf\x8d\x28\xee\xe8\x48\x4e\xd3\x9c\xe9\x30\x72\x2a\x98\x98\x5c\xae\x54\x79\x3d\x81\x78\xf2\xbd\x39\x11\x12\x85\x01\x3d\xd0\xb0\x04\xf2\x98\x34\x9d\xf9\x18\xf7\x9b\x44\xfd\x9d\x19\xa1\x32\x17\xaa\x8e\x8f\xf3\x54\x8c\x99\x35\x06\x2a\xc4\xb6\x4f\x5c\x80\x08\x6b\xf0\xbf\x9f\xae\xe8\xb9\xc0\x8d\x5a\x94\x03\x8d\xe1\x9d\xf8\xdf\x58\x6f\x45\x72\x0c\x65\x09\x32\xb7\xca\xfc\x73\x9a\xb8\x9d\x23\x91\x9f\xe9\xc4\x6c\xed\x67\xb3\xc1\x18\x16\x66\xa6\xd9\x0d\x0e\x91\xa4\x53\x93\x61\x44\x50\xf1\x16\x18\x3f\x0d\x6b\x69\x5e\x7f\x8b\x3d\xbb\x05\x83\x01\x33\xe9\xda\xdd\xe9\x38\x4d\x97\x11\xd8\x20\xf5\xa2\xbd\xbb\xae\x3a\x84\x5a\xe7\x55\x55\x88\xee\x5f\x45\x81\x0e\x44\xf1\x52\x46\xec\x38\xba\x89\xe6\xe7\xaf\xf7\x8e\xe6\x32\x7c\x2f\xf7\x67\x4d\x07\x7d\x60\xc6\xb1\xb2\x25\xed\x7d\x58\x0b\x1e\x34\x05\x87\x3e\xd2\x19\x20\xbd\x6f\x4b\x84\xfc\x7c\xc4\xcf\xee\xb2\x36\x35\x62\x20\x10\x15\x47\x9e\xd8\xa1\xbf\xa2\xb0\x1e\xd7\x21\xf6\x79\xff\x41\x80\x36\x75\x56\x30\x32\x1e\x0b\xd3\xfc\xe3\x11\x68\xa6\xa6\x55\xb1\x26\x3a\xc6\xc3\xce\x84\x19\xe4\x32\xe7\xde\x38\x29\x0d\x9c\x70\xdd\x87\x4c\x31\x20\xe0\x31\x58\x51\x68\xc4\x9e\x68\x51\xc0\x11\x87\x69\x28\x8b\xed\x72\x15\xa2\xf0\x3f\x8b\x3d\xd6\x58\x3d\x24\xfc\x07\xd1\x28\xba\xe3\x70\x95\x8d\x05\x7a\x4b\x75\x68\x6b\x38\x96\x09\xf9\x0d\x8d\xcc\xfc\xcf\xf5\x0b\x24\x24\xfc\xd8\xbf\xe0\x65\x34\xb6\x03\xa5\xee\x0b\x93\xc8\xc7\xb6\x17\xd2\xd9\xc4\x93\xd1\xb3\xb9\xdc\x6b\xad\xfe\xe4\x4d\xc2\x2a\x1a\x58\x81\xd6\xf1\x6c\xb3\x4c\x92\x05\x61\x75\x8d\xf1\x3c\x2e\xca\x8f\xef\x10\x90\xdc\xdc\xf9\x6c\x01\x4e\x5a\x51\x23\x5e\x48\x4e\xeb\x02\xe0\x0f\x01\x56\x5c\x3b\xbb\x60\xda\x48\x5e\x71\x25\xba\x56\xbb\x06\x2b\x85\xf3\x08\xae\x5f\x6c\x72\xe3\x63\x5c\x8e\xf2\x68\x1f\x89\xe9\x3b\x79\x06\xe5\xdb\xe8\xc0\x40\xd6\x18\xc2\x04\xf1\x08\x2a\x40\x53\x72\x8b\x9c\x38\x7d\xd2\x6c\x9c\x78\x21\x32\xc4\x97\x4d\xae\xe5\x44\x9b\xea\xff\x8b\x39\x32\xfa\x66\x41\x20\x0e\xb7\x5f\xbe\xa5\x61\x32\x1f\xf9\x30\x6f\xaf\x80\x78\xe6\x2a\xc1\x94\x1f\xa6\x91\xd6\x38\x62\x6a\xd1\x43\xa4\x3b\x44\x9e\x99\xa9\x99\x83\x0f\x5c\x93\x71\xbd\x65\xf6\x9c\xdd\xf8\x5b\x95\xf6\x57\xd6\x40\x8a\x21\xde\x67\x7e\xd4\xa5\x61\xa4\x52\x5c\xdc\x3d\xb9\x16\xbb\x87\x08\x80\x1f\x8b\xb7\x3e\xd2\x51\xef\x00\x7f\x41\xbd\x5a\xcc\x5d\xe5\x06\x04\x4c\x64\x90\x16\x77\xb4\xb8\x0e\x8d\x6f\x66\x52\xf5\xbe\xf2\xbc\xf7\x58\xd1\x67\xf1\x16\xbb\xb5\xa9\x37\xd8\x1d\xb5\x74\xff\x63\x7e\x04\x07\x29\xad\xad\xd2\xdc\x91\xaf\xbe\x20\x76\xaf\x03\x2a\x0c\x36\x6e\x8e\x4b\xc1\x29\x6a\x10\xf6\xf0\xf1\x01\x15\x96\x27\xbc\x6e\x42\x8d\x9b\xb8\x20\x54\x5b\x3e\x61\x5c\x55\x15\x45\x7b\x21\x51\xc2\xab\x1f\xf0\x47\x80\x9a\xa8\x42\x7f\x6e\x03\xc4\x1a\x68\xb2\x12\x63\x25\xd3\x92\x7f\xbf\x6e\xd7\x32\xc8\xca\xa2\x76\x1f\x5c\x98\x31\x87\x87\x6c\x81\xe4\x72\x74\xb5\x69\x91\xeb\xde\x68\xf4\x1f\xde\x84\xa4\x44\x1c\x75\x1c\x7c\x4f\x1f\x32\x80\x53\xe1\xbc\x13\xf1\x53\xde\x13\x3a\x4e\xee\x23\x1e\xba\xff\xb8\xbc\xca\x7b\xde\xfb\x21\xf4\x7f\x9b\x11\xb5\x7f\xa2\x36\x25\xc5\xce\x7e\xc9\x7b\x80\x00\x00\x00\x72\x67\x51\x0d\x67\x63\x03\x67\x13\x6e\x23\x47\x13\x03\x67\x13\x00\x33\x23\x13\x3b\x1d\x23\x17\x1d\x33\x9b\x0a\x13\x0b\x37\x33\x2b\x37\x2b\x23\x1d\x23\x07\x37\x23\xe3\x30\x55\x32\xc1\xff\x26\xd8\xd8\x19\x5b\x98\x7a\xfc\x9f\x02\x13\xd7\x7f\x0b\x96\xf0\x66\xe8\x00\x00\x00\xfd\xbf\x04\x13\x77\x0b\x53\x6e\x61\x3b\x6b\x3b\x47\x65\x7b\x03\x23\x13\x00\x3b\x1b\x1b\x0b\x1b\x8b\x17\xc0\x16\x00\x00\x10\xff\x0f\x20\x62\xe0\x6c\xa2\x62\x61\xf3\xbf\x3e\xc1\xcc\xcd\xc8\xc2\xcd\xc8\x46\xc4\xc4\xc1\xcd\xc6\xce\xcd\xc6\x6e\x28\x30\xd8\x01\x00\x00\xb0\xff\x07\x16\x75\xb7\x30\x95\xb4\x31\x30\x33\x91\x31\xb1\x35\x73\x36\x07\x30\x31\x72\xb1\x91\xd8\x4e\x41\x00\x00\x00\xac\xff\x13\x52\xb7\x30\xfe\x2f\x86\x85\x99\xbd\xe2\x0e\x7d\x17\x00\x00\xa0\xfe\x6f\x8c\xbc\xa9\xa9\x93\x89\x33\x80\x89\x9d\x73\x68\xca\x8c\x1f\x00\x00\xd0\xfd\xcf\xb3\xb2\x9d\xa9\xb3\x9b\x81\xa3\x09\x40\xd0\xd8\xce\xd0\x84\x48\xc1\xdc\xce\xd9\xce\xc9\xdc\xce\x9e\x48\x58\x99\x8d\x9e\x89\x48\xd6\xc0\xc8\xc2\xf6\xbf\x6e\x7e\xb3\xbb\x3c\x01\x00\x00\xbc\xff\x11\x9d\xcd\x5d\x6c\x0c\x6d\x0d\x2c\xac\xb9\x85\xed\x6c\xec\x1d\x4d\x9c\x9c\x2c\xec\x6c\x01\xec\x6f\x26\xf6\xea\x00\x00\x80\xea\x3f\x70\x52\x0a\xa2\xe2\x92\xb6\xce\x26\x8e\x46\xe6\x06\xb6\x66\x26\x62\x76\x8e\x36\x06\xce\x00\x16\x46\x76\x21\xc9\x5a\x11\x00\x00\xc0\xf0\xff\xd7\xf9\xbf\x47\xc2\xca\xc6\xc9\xd6\xdf\x0f\x3d\x04\x00\x00\x08\xff\x83\xaa\x64\xe2\x64\x67\xed\xe2\x6c\x61\x67\xab\x6a\x6b\xe1\x0c\x60\x26\x17\xd0\x5b\x00\x00\x00\x44\xff\x01\xd5\xf8\x7f\x58\x00\x3b\x23\x23\x03\xd3\x51\x34\xdf\xd1\xff\x07\xab\xf9\xff\x66\x0d\x69\x9e\x4a\x01\x00\x00\x40\x52\x54\x4e\xa4\x56\xe8\x4f\xe0\xff\x15\x00\x00\xff\xff\x5a\xc3\xba\x2a\x98\x3d\x00\x00")
 72 | 
 73 | func gopherPngBytes() ([]byte, error) {
 74 | 	return bindataRead(
 75 | 		_gopherPng,
 76 | 		"gopher.png",
 77 | 	)
 78 | }
 79 | 
 80 | func gopherPng() (*asset, error) {
 81 | 	bytes, err := gopherPngBytes()
 82 | 	if err != nil {
 83 | 		return nil, err
 84 | 	}
 85 | 
 86 | 	info := bindataFileInfo{name: "gopher.png", size: 15768, mode: os.FileMode(420), modTime: time.Unix(1474835119, 0)}
 87 | 	a := &asset{bytes: bytes, info: info}
 88 | 	return a, nil
 89 | }
 90 | 
 91 | // Asset loads and returns the asset for the given name.
 92 | // It returns an error if the asset could not be found or
 93 | // could not be loaded.
 94 | func Asset(name string) ([]byte, error) {
 95 | 	cannonicalName := strings.Replace(name, "\\", "/", -1)
 96 | 	if f, ok := _bindata[cannonicalName]; ok {
 97 | 		a, err := f()
 98 | 		if err != nil {
 99 | 			return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err)
100 | 		}
101 | 		return a.bytes, nil
102 | 	}
103 | 	return nil, fmt.Errorf("Asset %s not found", name)
104 | }
105 | 
106 | // MustAsset is like Asset but panics when Asset would return an error.
107 | // It simplifies safe initialization of global variables.
108 | func MustAsset(name string) []byte {
109 | 	a, err := Asset(name)
110 | 	if err != nil {
111 | 		panic("asset: Asset(" + name + "): " + err.Error())
112 | 	}
113 | 
114 | 	return a
115 | }
116 | 
117 | // AssetInfo loads and returns the asset info for the given name.
118 | // It returns an error if the asset could not be found or
119 | // could not be loaded.
120 | func AssetInfo(name string) (os.FileInfo, error) {
121 | 	cannonicalName := strings.Replace(name, "\\", "/", -1)
122 | 	if f, ok := _bindata[cannonicalName]; ok {
123 | 		a, err := f()
124 | 		if err != nil {
125 | 			return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err)
126 | 		}
127 | 		return a.info, nil
128 | 	}
129 | 	return nil, fmt.Errorf("AssetInfo %s not found", name)
130 | }
131 | 
132 | // AssetNames returns the names of the assets.
133 | func AssetNames() []string {
134 | 	names := make([]string, 0, len(_bindata))
135 | 	for name := range _bindata {
136 | 		names = append(names, name)
137 | 	}
138 | 	return names
139 | }
140 | 
141 | // _bindata is a table, holding each asset generator, mapped to its name.
142 | var _bindata = map[string]func() (*asset, error){
143 | 	"gopher.png": gopherPng,
144 | }
145 | 
146 | // AssetDir returns the file names below a certain
147 | // directory embedded in the file by go-bindata.
148 | // For example if you run go-bindata on data/... and data contains the
149 | // following hierarchy:
150 | //     data/
151 | //       foo.txt
152 | //       img/
153 | //         a.png
154 | //         b.png
155 | // then AssetDir("data") would return []string{"foo.txt", "img"}
156 | // AssetDir("data/img") would return []string{"a.png", "b.png"}
157 | // AssetDir("foo.txt") and AssetDir("notexist") would return an error
158 | // AssetDir("") will return []string{"data"}.
159 | func AssetDir(name string) ([]string, error) {
160 | 	node := _bintree
161 | 	if len(name) != 0 {
162 | 		cannonicalName := strings.Replace(name, "\\", "/", -1)
163 | 		pathList := strings.Split(cannonicalName, "/")
164 | 		for _, p := range pathList {
165 | 			node = node.Children[p]
166 | 			if node == nil {
167 | 				return nil, fmt.Errorf("Asset %s not found", name)
168 | 			}
169 | 		}
170 | 	}
171 | 	if node.Func != nil {
172 | 		return nil, fmt.Errorf("Asset %s not found", name)
173 | 	}
174 | 	rv := make([]string, 0, len(node.Children))
175 | 	for childName := range node.Children {
176 | 		rv = append(rv, childName)
177 | 	}
178 | 	return rv, nil
179 | }
180 | 
181 | type bintree struct {
182 | 	Func     func() (*asset, error)
183 | 	Children map[string]*bintree
184 | }
185 | var _bintree = &bintree{nil, map[string]*bintree{
186 | 	"gopher.png": &bintree{gopherPng, map[string]*bintree{}},
187 | }}
188 | 
189 | // RestoreAsset restores an asset under the given directory
190 | func RestoreAsset(dir, name string) error {
191 | 	data, err := Asset(name)
192 | 	if err != nil {
193 | 		return err
194 | 	}
195 | 	info, err := AssetInfo(name)
196 | 	if err != nil {
197 | 		return err
198 | 	}
199 | 	err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755))
200 | 	if err != nil {
201 | 		return err
202 | 	}
203 | 	err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
204 | 	if err != nil {
205 | 		return err
206 | 	}
207 | 	err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime())
208 | 	if err != nil {
209 | 		return err
210 | 	}
211 | 	return nil
212 | }
213 | 
214 | // RestoreAssets restores an asset under the given directory recursively
215 | func RestoreAssets(dir, name string) error {
216 | 	children, err := AssetDir(name)
217 | 	// File
218 | 	if err != nil {
219 | 		return RestoreAsset(dir, name)
220 | 	}
221 | 	// Dir
222 | 	for _, child := range children {
223 | 		err = RestoreAssets(dir, filepath.Join(name, child))
224 | 		if err != nil {
225 | 			return err
226 | 		}
227 | 	}
228 | 	return nil
229 | }
230 | 
231 | func _filePath(dir, name string) string {
232 | 	cannonicalName := strings.Replace(name, "\\", "/", -1)
233 | 	return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...)
234 | }
235 | 
236 | 


--------------------------------------------------------------------------------
/examples/desktop-notification/gopher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexflint/gallium/bfa1ecd9241eb3b9f203869fb317c55c3c0c360f/examples/desktop-notification/gopher.png


--------------------------------------------------------------------------------
/examples/desktop-notification/notification.go:
--------------------------------------------------------------------------------
 1 | //go:generate go-bindata -o bindata.go gopher.png
 2 | 
 3 | package main
 4 | 
 5 | import (
 6 | 	"log"
 7 | 	"os"
 8 | 	"runtime"
 9 | 
10 | 	"github.com/alexflint/gallium"
11 | )
12 | 
13 | func main() {
14 | 	runtime.LockOSThread()
15 | 	gallium.RedirectStdoutStderr(os.ExpandEnv("$HOME/Library/Logs/Gallium.log"))
16 | 	gallium.Loop(os.Args, onReady)
17 | }
18 | 
19 | func onReady(app *gallium.App) {
20 | 	img, err := gallium.ImageFromPNG(MustAsset("gopher.png"))
21 | 	if err != nil {
22 | 		log.Println(err)
23 | 		os.Exit(1)
24 | 	}
25 | 
26 | 	app.Post(gallium.Notification{
27 | 		Title:    "Wow this is a notification",
28 | 		Subtitle: "The subtitle",
29 | 		Image:    img,
30 | 	})
31 | }
32 | 


--------------------------------------------------------------------------------
/examples/frameless/frameless.go:
--------------------------------------------------------------------------------
 1 | package main
 2 | 
 3 | import (
 4 | 	"fmt"
 5 | 	"net/http"
 6 | 	"os"
 7 | 	"runtime"
 8 | 
 9 | 	"github.com/alexflint/gallium"
10 | )
11 | 
12 | var index = `<!doctype html>
13 | <html><head></head><body>
14 | <textarea rows="10" cols="80"></textarea>
15 | </body></html>`
16 | 
17 | func main() {
18 | 	runtime.LockOSThread()
19 | 	gallium.RedirectStdoutStderr(os.ExpandEnv("$HOME/Library/Logs/Gallium.log"))
20 | 	gallium.Loop(os.Args, onReady)
21 | }
22 | 
23 | func handleIndex(w http.ResponseWriter, r *http.Request) {
24 | 	fmt.Fprint(w, index)
25 | }
26 | 
27 | func onReady(app *gallium.App) {
28 | 	http.HandleFunc("/", handleIndex)
29 | 	go http.ListenAndServe(":8967", nil)
30 | 
31 | 	opt := gallium.FramelessWindow
32 | 	opt.Title = "Frameless Window"
33 | 	_, err := app.OpenWindow("http://127.0.0.1:8967/", opt)
34 | 	if err != nil {
35 | 		fmt.Println(err)
36 | 		os.Exit(1)
37 | 	}
38 | }
39 | 


--------------------------------------------------------------------------------
/examples/keys/keys.go:
--------------------------------------------------------------------------------
 1 | package main
 2 | 
 3 | import (
 4 | 	"log"
 5 | 	"os"
 6 | 	"runtime"
 7 | 
 8 | 	"github.com/alexflint/gallium"
 9 | )
10 | 
11 | func handleMenuFirst() {
12 | 	log.Println("menu shortcut: first")
13 | }
14 | 
15 | func handleMenuSecond() {
16 | 	log.Println("menu shortcut: second")
17 | }
18 | 
19 | func handleMenuQuit() {
20 | 	os.Exit(0)
21 | }
22 | 
23 | func onReady(app *gallium.App) {
24 | 	gallium.AddGlobalShortcut(gallium.MustParseKeys("shift cmd u"), func() {
25 | 		log.Println("global shortcut: U")
26 | 	})
27 | 	gallium.AddGlobalShortcut(gallium.MustParseKeys("shift cmd o"), func() {
28 | 		log.Println("global shortcut: O")
29 | 	})
30 | 	app.SetMenu([]gallium.Menu{
31 | 		{
32 | 			Title: "Shortcut",
33 | 			Entries: []gallium.MenuEntry{
34 | 				gallium.MenuItem{
35 | 					Title:    "First",
36 | 					Shortcut: gallium.MustParseKeys("cmd 1"),
37 | 					OnClick:  handleMenuFirst,
38 | 				},
39 | 				gallium.MenuItem{
40 | 					Title:    "Second",
41 | 					Shortcut: gallium.MustParseKeys("cmd 2"),
42 | 					OnClick:  handleMenuSecond,
43 | 				},
44 | 				gallium.MenuItem{
45 | 					Title:    "Quit",
46 | 					Shortcut: gallium.MustParseKeys("cmd q"),
47 | 					OnClick:  handleMenuQuit,
48 | 				},
49 | 			},
50 | 		},
51 | 	})
52 | }
53 | 
54 | func main() {
55 | 	runtime.LockOSThread()
56 | 	gallium.RedirectStdoutStderr(os.ExpandEnv("$HOME/Library/Logs/Gallium.log"))
57 | 	gallium.Loop(os.Args, onReady)
58 | }
59 | 


--------------------------------------------------------------------------------
/examples/menu/menu.go:
--------------------------------------------------------------------------------
 1 | package main
 2 | 
 3 | import (
 4 | 	"log"
 5 | 	"os"
 6 | 	"runtime"
 7 | 
 8 | 	"github.com/alexflint/gallium"
 9 | )
10 | 
11 | func main() {
12 | 	runtime.LockOSThread()
13 | 	gallium.Loop(os.Args, onReady)
14 | }
15 | 
16 | func onReady(app *gallium.App) {
17 | 	app.OpenWindow("http://example.com/", gallium.FramedWindow)
18 | 	app.SetMenu([]gallium.Menu{
19 | 		gallium.Menu{
20 | 			Title: "demo",
21 | 			Entries: []gallium.MenuEntry{
22 | 				gallium.MenuItem{
23 | 					Title:   "About",
24 | 					OnClick: handleMenuAbout,
25 | 				},
26 | 				gallium.Separator,
27 | 				gallium.MenuItem{
28 | 					Title:    "Quit",
29 | 					Shortcut: gallium.MustParseKeys("cmd q"),
30 | 					OnClick:  handleMenuQuit,
31 | 				},
32 | 			},
33 | 		},
34 | 	})
35 | }
36 | 
37 | func handleMenuAbout() {
38 | 	log.Println("about clicked")
39 | 	os.Exit(0)
40 | }
41 | 
42 | func handleMenuQuit() {
43 | 	log.Println("quit clicked")
44 | 	os.Exit(0)
45 | }
46 | 


--------------------------------------------------------------------------------
/examples/native/native.go:
--------------------------------------------------------------------------------
 1 | package main
 2 | 
 3 | import (
 4 | 	"log"
 5 | 	"os"
 6 | 	"runtime"
 7 | 
 8 | 	"github.com/alexflint/gallium"
 9 | )
10 | 
11 | /*
12 | #cgo CFLAGS: -x objective-c
13 | #cgo CFLAGS: -framework Cocoa
14 | #cgo LDFLAGS: -framework Cocoa
15 | 
16 | #include <Cocoa/Cocoa.h>
17 | #include <dispatch/dispatch.h>
18 | 
19 | void SetAlpha(void* window, float alpha) {
20 |   // Cocoa requires that all UI operations happen on the main thread. Since
21 |   // gallium.Loop will have initiated the Cocoa event loop, we can can use
22 |   // dispatch_async to run code on the main thread.
23 |   dispatch_async(dispatch_get_main_queue(), ^{
24 | 	NSWindow* w = (NSWindow*)window;
25 | 	[w setAlphaValue:alpha];
26 |   });
27 | }
28 | */
29 | import "C"
30 | 
31 | func onReady(ui *gallium.App) {
32 | 	window, err := ui.OpenWindow("http://example.com/", gallium.FramedWindow)
33 | 	if err != nil {
34 | 		log.Fatal(err)
35 | 	}
36 | 	C.SetAlpha(window.NativeWindow(), 0.5)
37 | }
38 | 
39 | func main() {
40 | 	runtime.LockOSThread()
41 | 	gallium.RedirectStdoutStderr(os.ExpandEnv("$HOME/Library/Logs/Gallium.log"))
42 | 	gallium.Loop(os.Args, onReady)
43 | }
44 | 


--------------------------------------------------------------------------------
/examples/screens/screens.go:
--------------------------------------------------------------------------------
 1 | package main
 2 | 
 3 | import (
 4 | 	"os"
 5 | 	"runtime"
 6 | 
 7 | 	"github.com/alexflint/gallium"
 8 | 	"github.com/kr/pretty"
 9 | )
10 | 
11 | func onReady(app *gallium.App) {
12 | 	pretty.Println(gallium.FocusedScreen())
13 | 	pretty.Println(gallium.Screens())
14 | }
15 | 
16 | func main() {
17 | 	runtime.LockOSThread()
18 | 	gallium.RedirectStdoutStderr(os.ExpandEnv("$HOME/Library/Logs/Gallium.log"))
19 | 	gallium.Loop(os.Args, onReady)
20 | }
21 | 


--------------------------------------------------------------------------------
/examples/simple/gopher.iconset/icon_128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexflint/gallium/bfa1ecd9241eb3b9f203869fb317c55c3c0c360f/examples/simple/gopher.iconset/icon_128x128.png


--------------------------------------------------------------------------------
/examples/simple/gopher.iconset/icon_128x128@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexflint/gallium/bfa1ecd9241eb3b9f203869fb317c55c3c0c360f/examples/simple/gopher.iconset/icon_128x128@2x.png


--------------------------------------------------------------------------------
/examples/simple/gopher.iconset/icon_16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexflint/gallium/bfa1ecd9241eb3b9f203869fb317c55c3c0c360f/examples/simple/gopher.iconset/icon_16x16.png


--------------------------------------------------------------------------------
/examples/simple/gopher.iconset/icon_16x16@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexflint/gallium/bfa1ecd9241eb3b9f203869fb317c55c3c0c360f/examples/simple/gopher.iconset/icon_16x16@2x.png


--------------------------------------------------------------------------------
/examples/simple/gopher.iconset/icon_256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexflint/gallium/bfa1ecd9241eb3b9f203869fb317c55c3c0c360f/examples/simple/gopher.iconset/icon_256x256.png


--------------------------------------------------------------------------------
/examples/simple/gopher.iconset/icon_256x256@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexflint/gallium/bfa1ecd9241eb3b9f203869fb317c55c3c0c360f/examples/simple/gopher.iconset/icon_256x256@2x.png


--------------------------------------------------------------------------------
/examples/simple/gopher.iconset/icon_32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexflint/gallium/bfa1ecd9241eb3b9f203869fb317c55c3c0c360f/examples/simple/gopher.iconset/icon_32x32.png


--------------------------------------------------------------------------------
/examples/simple/gopher.iconset/icon_32x32@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexflint/gallium/bfa1ecd9241eb3b9f203869fb317c55c3c0c360f/examples/simple/gopher.iconset/icon_32x32@2x.png


--------------------------------------------------------------------------------
/examples/simple/gopher.iconset/icon_512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexflint/gallium/bfa1ecd9241eb3b9f203869fb317c55c3c0c360f/examples/simple/gopher.iconset/icon_512x512.png


--------------------------------------------------------------------------------
/examples/simple/simple.go:
--------------------------------------------------------------------------------
 1 | package main
 2 | 
 3 | import (
 4 | 	"log"
 5 | 	"os"
 6 | 	"runtime"
 7 | 
 8 | 	"github.com/alexflint/gallium"
 9 | )
10 | 
11 | func main() {
12 | 	runtime.LockOSThread()
13 | 	gallium.RedirectStdoutStderr(os.ExpandEnv("$HOME/Library/Logs/Gallium.log"))
14 | 	gallium.Loop(os.Args, onReady)
15 | }
16 | 
17 | func handleMenuQuit() {
18 | 	log.Println("quit clicked")
19 | 	os.Exit(0)
20 | }
21 | 
22 | func handleDoSomething() {
23 | 	log.Println("do something")
24 | }
25 | 
26 | func handleDoSomethingElse() {
27 | 	log.Println("do something else")
28 | }
29 | 
30 | func onReady(app *gallium.App) {
31 | 	app.OpenWindow("http://example.com/", gallium.FramedWindow)
32 | 	app.SetMenu([]gallium.Menu{
33 | 		{
34 | 			Title: "demo",
35 | 			Entries: []gallium.MenuEntry{
36 | 				gallium.MenuItem{
37 | 					Title:    "Quit",
38 | 					Shortcut: gallium.MustParseKeys("cmd q"),
39 | 					OnClick:  handleMenuQuit,
40 | 				},
41 | 			},
42 | 		},
43 | 	})
44 | }
45 | 


--------------------------------------------------------------------------------
/examples/statusbar/bindata.go:
--------------------------------------------------------------------------------
  1 | // Code generated by go-bindata.
  2 | // sources:
  3 | // icon.png
  4 | // DO NOT EDIT!
  5 | 
  6 | package main
  7 | 
  8 | import (
  9 | 	"bytes"
 10 | 	"compress/gzip"
 11 | 	"fmt"
 12 | 	"io"
 13 | 	"io/ioutil"
 14 | 	"os"
 15 | 	"path/filepath"
 16 | 	"strings"
 17 | 	"time"
 18 | )
 19 | 
 20 | func bindataRead(data []byte, name string) ([]byte, error) {
 21 | 	gz, err := gzip.NewReader(bytes.NewBuffer(data))
 22 | 	if err != nil {
 23 | 		return nil, fmt.Errorf("Read %q: %v", name, err)
 24 | 	}
 25 | 
 26 | 	var buf bytes.Buffer
 27 | 	_, err = io.Copy(&buf, gz)
 28 | 	clErr := gz.Close()
 29 | 
 30 | 	if err != nil {
 31 | 		return nil, fmt.Errorf("Read %q: %v", name, err)
 32 | 	}
 33 | 	if clErr != nil {
 34 | 		return nil, err
 35 | 	}
 36 | 
 37 | 	return buf.Bytes(), nil
 38 | }
 39 | 
 40 | type asset struct {
 41 | 	bytes []byte
 42 | 	info  os.FileInfo
 43 | }
 44 | 
 45 | type bindataFileInfo struct {
 46 | 	name    string
 47 | 	size    int64
 48 | 	mode    os.FileMode
 49 | 	modTime time.Time
 50 | }
 51 | 
 52 | func (fi bindataFileInfo) Name() string {
 53 | 	return fi.name
 54 | }
 55 | func (fi bindataFileInfo) Size() int64 {
 56 | 	return fi.size
 57 | }
 58 | func (fi bindataFileInfo) Mode() os.FileMode {
 59 | 	return fi.mode
 60 | }
 61 | func (fi bindataFileInfo) ModTime() time.Time {
 62 | 	return fi.modTime
 63 | }
 64 | func (fi bindataFileInfo) IsDir() bool {
 65 | 	return false
 66 | }
 67 | func (fi bindataFileInfo) Sys() interface{} {
 68 | 	return nil
 69 | }
 70 | 
 71 | var _iconPng = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x00\x4e\x04\xb1\xfb\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\x00\x00\x1d\x00\x00\x00\x16\x08\x04\x00\x00\x00\x96\x5d\x5f\x47\x00\x00\x00\x04\x67\x41\x4d\x41\x00\x00\xb1\x8f\x0b\xfc\x61\x05\x00\x00\x00\x02\x62\x4b\x47\x44\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x07\x74\x49\x4d\x45\x07\xe0\x0a\x03\x09\x1b\x21\x68\x1b\xe6\x26\x00\x00\x03\x82\x49\x44\x41\x54\x38\xcb\x9d\x94\xcd\x6f\x1b\x55\x14\xc5\xcf\x9b\x4f\x7b\x66\x6c\x8f\x63\x3b\x6e\x1c\x27\x4d\xf3\xe9\xb4\x4d\x14\xa9\x6a\x25\xda\x00\x69\xa4\x46\x08\x44\x16\x50\xb5\x12\x74\x8b\xba\x83\x15\x42\xfd\x03\xd8\xc1\x82\x15\x2b\xd8\xb4\xaa\x10\xac\x2a\x0a\x8b\x22\x01\x69\x48\x9b\x28\x44\x85\x24\x28\xa9\x13\xc7\xce\x87\x93\xd8\x8e\x63\x7b\x9c\xf1\x8c\xc7\x33\x7e\x2c\x02\xc8\x49\x0a\x0b\xde\xee\x2c\x7e\xba\xe7\xbe\xab\x73\x80\xff\xfd\x48\xa3\xb8\x08\x46\xe6\x83\xe2\xae\xab\x56\xf2\x56\x79\x17\x91\x1c\xce\x64\x0c\xab\x3e\x4d\x08\x05\x8a\xff\x85\x8e\xc1\x19\xf2\xb5\x70\x9c\xc9\x56\x4a\xfc\x9e\x87\xa1\x12\x91\x44\x42\x2d\xe9\x54\x66\xd6\x49\x3e\x3c\x86\x72\x8d\x42\x80\x95\x8a\xf4\xa9\x7a\xe2\xd9\x83\xf5\x0f\xf0\x11\x3e\x46\x27\x93\x93\xf6\x06\xd9\x3e\x79\x99\x39\x61\x98\x6d\x14\xdd\x80\x88\x76\x76\xb6\xb4\x65\xe2\x6b\xdc\x27\x69\xf7\x32\xb3\x60\xb4\x6d\x92\x0d\xd2\x5d\xcd\xf3\x66\x0c\xa9\x17\xa3\xb7\xb1\x84\xd0\x79\xf7\x82\x95\xb9\x8f\x32\x44\x55\xb9\xac\xc6\x82\x3d\x11\x39\x9d\xd9\x28\x34\x45\xaa\xd1\x30\x53\x29\x74\x34\xc0\x6c\xe3\xcc\x40\x88\x06\x47\xe3\x04\x02\x1c\x4e\xb9\xac\xac\x06\xe2\xc4\x12\xfd\x94\x0d\x14\x60\x9b\xb6\x57\x51\x18\x49\x5b\x3c\xbe\xeb\xab\x90\xb0\xc3\x46\xfa\xa5\xc4\x24\xee\x62\x1c\x82\xdf\x67\xa7\xd6\xf5\x3b\xcc\x9b\xcc\x2d\xc7\x15\xf2\x78\x82\x94\xaf\x8c\x38\x8b\x74\xeb\xd8\x37\x8d\x80\x61\xb8\x2e\xb9\x0d\xc1\xe1\x5f\x34\x00\x04\x4e\x45\x77\xc7\x5c\xab\x0b\xae\x72\x90\x68\xa2\x34\x44\x78\xde\xd8\x7e\xe2\xc4\x9d\xa3\xbb\x5e\xc3\x38\x8c\x2b\x4d\x51\x6b\xcb\x95\x5d\xc9\x7e\x06\x40\x47\x73\x2d\xcf\x18\x97\xfc\xd9\xda\x8e\xa5\x76\x09\x51\x58\x82\xae\x66\xe6\x57\x72\x32\x39\x8b\xe7\x7f\xa1\x0c\x50\xc5\xb7\xaa\xda\x3b\xfa\x13\x5b\xe7\x74\x09\x00\xb0\x85\x35\x4c\xc4\xad\xc7\x85\x82\xb6\xbd\x32\xdd\xbc\x5c\xea\xd0\x06\xa4\xa9\x87\x7b\x37\x87\xaf\xdd\xcc\xbb\xc7\xc8\x6b\x7f\x4f\x8d\x81\x0b\x0b\xe4\x6c\x66\x52\x77\xb5\xfa\xb2\xfd\xf4\x77\x00\x39\x00\x89\xea\xea\x7e\xb2\xb4\x5b\xef\xa8\x1c\xec\xda\x9e\xac\xda\xd9\x55\xf5\x95\xeb\x55\xb1\x2e\x5b\xe5\x33\xf5\x14\x18\xc0\x81\x51\xd0\x05\xb3\xe7\xb6\x96\x2b\x6f\x5f\xa1\x03\xaf\x7b\xde\x38\x72\xfa\x2a\xaa\x54\x63\x59\x23\x94\xf7\x79\x58\xed\xbb\x39\x41\xf7\x76\xba\x0e\x0d\xb3\x18\xd0\xf4\xfc\x3c\xdf\xc2\x8c\xc6\xdd\x6e\x7a\xc1\x18\xe6\xbb\x6f\xf1\x0a\xbe\x01\x00\xbc\x8f\x90\x60\xb4\xd6\xa6\xb8\xa7\xf4\x40\x69\x57\x94\x2f\xa5\xa1\x41\xb7\x18\x38\x34\x9c\x40\x04\x4c\xa9\x7c\xf5\x59\x36\x5d\xe2\xcc\x72\x56\x5f\xb7\xc3\x46\x5f\xac\x39\xc9\x9e\x43\xbb\xc8\xf8\x9d\xd3\xb5\x2d\x21\x9b\xe2\x10\x71\x3c\x84\xc9\x0f\x1d\x54\x72\x33\xf5\xfa\xd2\xe1\x71\x38\xb8\xe5\xa0\xba\xde\x65\xd2\xf7\xbc\x5e\x5d\xc8\x25\x77\x3e\x17\xd1\x62\xf9\x2d\xd9\xe4\x59\x9b\xa4\x7c\xda\x5d\xbc\xd5\x6b\x17\xb5\x7b\x07\x72\xa9\x36\x53\x51\x69\xf2\x30\x39\xc3\x70\x02\x83\xef\x76\x9b\x1f\x7e\xf1\x4a\x4f\x8b\xff\xaa\x14\x35\x2b\xf3\xd3\xd6\x60\x6d\xbb\x7e\x07\x04\x8b\x38\x8f\xc7\xdc\xec\xc0\x52\x74\xe6\xfb\x4e\xe7\xc1\xd1\xd0\x8d\x00\xdd\xb1\x1b\xa7\xec\xde\x4f\xdf\x71\x5e\x52\xa5\x96\x36\x85\x2d\x71\x56\xaf\x2d\x13\x43\x68\xab\x13\x52\x50\x32\xe1\x34\x9b\x7b\x2a\x96\xee\x1d\xcf\xeb\xcb\x98\xc4\x27\xae\x3f\x2e\xed\x17\x2f\x2e\x24\xe8\x6f\x08\xbb\x45\x3f\x95\x29\x27\x82\x32\xaa\xc7\xee\xa7\x99\xe2\x4e\xfe\xb9\x54\xf9\xe1\x64\xe8\x36\x00\xec\xda\x4b\x9b\x5e\x7f\xae\x9d\x58\x86\xf1\xa3\x7d\xa1\xac\x16\x6a\x1a\xb5\x2c\xa5\xd0\x5e\x5c\x6b\x9a\xfa\x2a\x7d\xba\xf6\xf3\xbf\x17\xcc\x18\x1e\x61\xfc\x1c\x6d\x35\x17\xcb\x1d\xae\x32\xeb\x88\x8a\xb7\x4f\x0e\x65\x26\xce\xcc\x3d\xc1\xdc\x0b\xbb\xe9\x9f\x96\x78\x84\xeb\x40\xc5\xdd\xcc\x0f\xef\x4f\x38\x1a\x75\x04\xa7\xb6\x69\xbf\xcd\xee\xaf\xe1\xd7\x93\x4d\x04\x00\xf8\x13\x01\xc9\x7f\x2a\x56\x02\x5e\xab\x00\x00\x00\x25\x74\x45\x58\x74\x64\x61\x74\x65\x3a\x63\x72\x65\x61\x74\x65\x00\x32\x30\x31\x36\x2d\x31\x30\x2d\x30\x33\x54\x30\x39\x3a\x32\x37\x3a\x33\x33\x2d\x30\x37\x3a\x30\x30\x8d\xeb\xe4\x71\x00\x00\x00\x25\x74\x45\x58\x74\x64\x61\x74\x65\x3a\x6d\x6f\x64\x69\x66\x79\x00\x32\x30\x31\x36\x2d\x31\x30\x2d\x30\x33\x54\x30\x39\x3a\x32\x37\x3a\x33\x33\x2d\x30\x37\x3a\x30\x30\xfc\xb6\x5c\xcd\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\x01\x00\x00\xff\xff\xce\x59\xde\xaa\x4e\x04\x00\x00")
 72 | 
 73 | func iconPngBytes() ([]byte, error) {
 74 | 	return bindataRead(
 75 | 		_iconPng,
 76 | 		"icon.png",
 77 | 	)
 78 | }
 79 | 
 80 | func iconPng() (*asset, error) {
 81 | 	bytes, err := iconPngBytes()
 82 | 	if err != nil {
 83 | 		return nil, err
 84 | 	}
 85 | 
 86 | 	info := bindataFileInfo{name: "icon.png", size: 1102, mode: os.FileMode(420), modTime: time.Unix(1475512090, 0)}
 87 | 	a := &asset{bytes: bytes, info: info}
 88 | 	return a, nil
 89 | }
 90 | 
 91 | // Asset loads and returns the asset for the given name.
 92 | // It returns an error if the asset could not be found or
 93 | // could not be loaded.
 94 | func Asset(name string) ([]byte, error) {
 95 | 	cannonicalName := strings.Replace(name, "\\", "/", -1)
 96 | 	if f, ok := _bindata[cannonicalName]; ok {
 97 | 		a, err := f()
 98 | 		if err != nil {
 99 | 			return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err)
100 | 		}
101 | 		return a.bytes, nil
102 | 	}
103 | 	return nil, fmt.Errorf("Asset %s not found", name)
104 | }
105 | 
106 | // MustAsset is like Asset but panics when Asset would return an error.
107 | // It simplifies safe initialization of global variables.
108 | func MustAsset(name string) []byte {
109 | 	a, err := Asset(name)
110 | 	if err != nil {
111 | 		panic("asset: Asset(" + name + "): " + err.Error())
112 | 	}
113 | 
114 | 	return a
115 | }
116 | 
117 | // AssetInfo loads and returns the asset info for the given name.
118 | // It returns an error if the asset could not be found or
119 | // could not be loaded.
120 | func AssetInfo(name string) (os.FileInfo, error) {
121 | 	cannonicalName := strings.Replace(name, "\\", "/", -1)
122 | 	if f, ok := _bindata[cannonicalName]; ok {
123 | 		a, err := f()
124 | 		if err != nil {
125 | 			return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err)
126 | 		}
127 | 		return a.info, nil
128 | 	}
129 | 	return nil, fmt.Errorf("AssetInfo %s not found", name)
130 | }
131 | 
132 | // AssetNames returns the names of the assets.
133 | func AssetNames() []string {
134 | 	names := make([]string, 0, len(_bindata))
135 | 	for name := range _bindata {
136 | 		names = append(names, name)
137 | 	}
138 | 	return names
139 | }
140 | 
141 | // _bindata is a table, holding each asset generator, mapped to its name.
142 | var _bindata = map[string]func() (*asset, error){
143 | 	"icon.png": iconPng,
144 | }
145 | 
146 | // AssetDir returns the file names below a certain
147 | // directory embedded in the file by go-bindata.
148 | // For example if you run go-bindata on data/... and data contains the
149 | // following hierarchy:
150 | //     data/
151 | //       foo.txt
152 | //       img/
153 | //         a.png
154 | //         b.png
155 | // then AssetDir("data") would return []string{"foo.txt", "img"}
156 | // AssetDir("data/img") would return []string{"a.png", "b.png"}
157 | // AssetDir("foo.txt") and AssetDir("notexist") would return an error
158 | // AssetDir("") will return []string{"data"}.
159 | func AssetDir(name string) ([]string, error) {
160 | 	node := _bintree
161 | 	if len(name) != 0 {
162 | 		cannonicalName := strings.Replace(name, "\\", "/", -1)
163 | 		pathList := strings.Split(cannonicalName, "/")
164 | 		for _, p := range pathList {
165 | 			node = node.Children[p]
166 | 			if node == nil {
167 | 				return nil, fmt.Errorf("Asset %s not found", name)
168 | 			}
169 | 		}
170 | 	}
171 | 	if node.Func != nil {
172 | 		return nil, fmt.Errorf("Asset %s not found", name)
173 | 	}
174 | 	rv := make([]string, 0, len(node.Children))
175 | 	for childName := range node.Children {
176 | 		rv = append(rv, childName)
177 | 	}
178 | 	return rv, nil
179 | }
180 | 
181 | type bintree struct {
182 | 	Func     func() (*asset, error)
183 | 	Children map[string]*bintree
184 | }
185 | var _bintree = &bintree{nil, map[string]*bintree{
186 | 	"icon.png": &bintree{iconPng, map[string]*bintree{}},
187 | }}
188 | 
189 | // RestoreAsset restores an asset under the given directory
190 | func RestoreAsset(dir, name string) error {
191 | 	data, err := Asset(name)
192 | 	if err != nil {
193 | 		return err
194 | 	}
195 | 	info, err := AssetInfo(name)
196 | 	if err != nil {
197 | 		return err
198 | 	}
199 | 	err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755))
200 | 	if err != nil {
201 | 		return err
202 | 	}
203 | 	err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
204 | 	if err != nil {
205 | 		return err
206 | 	}
207 | 	err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime())
208 | 	if err != nil {
209 | 		return err
210 | 	}
211 | 	return nil
212 | }
213 | 
214 | // RestoreAssets restores an asset under the given directory recursively
215 | func RestoreAssets(dir, name string) error {
216 | 	children, err := AssetDir(name)
217 | 	// File
218 | 	if err != nil {
219 | 		return RestoreAsset(dir, name)
220 | 	}
221 | 	// Dir
222 | 	for _, child := range children {
223 | 		err = RestoreAssets(dir, filepath.Join(name, child))
224 | 		if err != nil {
225 | 			return err
226 | 		}
227 | 	}
228 | 	return nil
229 | }
230 | 
231 | func _filePath(dir, name string) string {
232 | 	cannonicalName := strings.Replace(name, "\\", "/", -1)
233 | 	return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...)
234 | }
235 | 
236 | 


--------------------------------------------------------------------------------
/examples/statusbar/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexflint/gallium/bfa1ecd9241eb3b9f203869fb317c55c3c0c360f/examples/statusbar/icon.png


--------------------------------------------------------------------------------
/examples/statusbar/statusbar.go:
--------------------------------------------------------------------------------
 1 | //go:generate go-bindata -o bindata.go icon.png
 2 | 
 3 | package main
 4 | 
 5 | import (
 6 | 	"fmt"
 7 | 	"log"
 8 | 	"os"
 9 | 	"runtime"
10 | 
11 | 	"github.com/alexflint/gallium"
12 | )
13 | 
14 | func main() {
15 | 	runtime.LockOSThread()
16 | 	gallium.RedirectStdoutStderr(os.ExpandEnv("$HOME/Library/Logs/Gallium.log"))
17 | 	gallium.Loop(os.Args, onReady)
18 | }
19 | 
20 | func handleMenuQuit() {
21 | 	log.Println("quit clicked")
22 | 	os.Exit(0)
23 | }
24 | 
25 | func handleDoSomething() {
26 | 	log.Println("do something")
27 | }
28 | 
29 | func handleDoSomethingElse() {
30 | 	log.Println("do something else")
31 | }
32 | 
33 | func onReady(app *gallium.App) {
34 | 	img, err := gallium.ImageFromPNG(MustAsset("icon.png"))
35 | 	if err != nil {
36 | 		fmt.Println("unable to decode icon-gray.png:", err)
37 | 		os.Exit(1)
38 | 	}
39 | 
40 | 	app.AddStatusItem(gallium.StatusItemOptions{
41 | 		Image:     img,
42 | 		Width:     27.5,
43 | 		Highlight: true,
44 | 		Menu: []gallium.MenuEntry{
45 | 			gallium.MenuItem{Title: "Do something", OnClick: handleDoSomething},
46 | 			gallium.MenuItem{Title: "Do something else", OnClick: handleDoSomethingElse},
47 | 		},
48 | 	})
49 | }
50 | 


--------------------------------------------------------------------------------
/examples/window/window.go:
--------------------------------------------------------------------------------
 1 | package main
 2 | 
 3 | import (
 4 | 	"fmt"
 5 | 	"os"
 6 | 	"runtime"
 7 | 
 8 | 	"github.com/alexflint/gallium"
 9 | )
10 | 
11 | func init() {
12 | 	gallium.RedirectStdoutStderr(os.ExpandEnv("$HOME/Library/Logs/Gallium.log"))
13 | }
14 | 
15 | func main() {
16 | 	runtime.LockOSThread()
17 | 	gallium.Loop(os.Args, onReady)
18 | }
19 | 
20 | func onReady(app *gallium.App) {
21 | 	opt := gallium.FramedWindow
22 | 	opt.Title = "Framed Window"
23 | 	_, err := app.OpenWindow("http://example.com/", opt)
24 | 	if err != nil {
25 | 		fmt.Println(err)
26 | 		os.Exit(1)
27 | 	}
28 | 
29 | 	opt = gallium.FramelessWindow
30 | 	opt.Title = "Frameless Window"
31 | 	_, err = app.OpenWindow("http://example.com/", opt)
32 | 	if err != nil {
33 | 		fmt.Println(err)
34 | 		os.Exit(1)
35 | 	}
36 | }
37 | 


--------------------------------------------------------------------------------
/globalshortcut.go:
--------------------------------------------------------------------------------
  1 | package gallium
  2 | 
  3 | /*
  4 | #cgo CFLAGS: -mmacosx-version-min=10.8
  5 | #cgo CFLAGS: -DGALLIUM_DIR=${SRCDIR}
  6 | #cgo CFLAGS: -Idist/include
  7 | 
  8 | #include <stdlib.h>
  9 | #include "gallium/globalshortcut.h"
 10 | 
 11 | extern void cgo_onGlobalShortcut(int64_t);
 12 | 
 13 | // This is a wrapper around NSMenu_AddMenuItem that adds the function pointer
 14 | // argument, since this does not seem to be possible from Go directly.
 15 | static inline void helper_AddGlobalShortcut(
 16 | 	int ID,
 17 | 	const char* shortcutKey,
 18 | 	gallium_modifier_t shortcutModifier) {
 19 | 
 20 | 	GalliumAddGlobalShortcut(
 21 | 		ID,
 22 | 		shortcutKey,
 23 | 		shortcutModifier,
 24 | 		&cgo_onGlobalShortcut);
 25 | }
 26 | */
 27 | import "C"
 28 | import (
 29 | 	"errors"
 30 | 	"fmt"
 31 | 	"log"
 32 | 	"strings"
 33 | )
 34 | 
 35 | var (
 36 | 	nextID   int
 37 | 	handlers = make(map[int]func())
 38 | )
 39 | 
 40 | //export cgo_onGlobalShortcut
 41 | func cgo_onGlobalShortcut(id int) {
 42 | 	fmt.Println("cgo_onGlobalShortcut received ID", id)
 43 | 	if handler, found := handlers[id]; found {
 44 | 		handler()
 45 | 	} else {
 46 | 		log.Println("no handler for global shortcut ID", id)
 47 | 	}
 48 | }
 49 | 
 50 | // Modifier represents zero or more modifier keys (control, shift, option, etc)
 51 | type Modifier int
 52 | 
 53 | // these must be kept in sync with the gallium_modifier_t enum in cocoa.h
 54 | const (
 55 | 	ModifierCmd Modifier = 1 << iota
 56 | 	ModifierCtrl
 57 | 	ModifierCmdOrCtrl
 58 | 	ModifierAltOrOption
 59 | 	ModifierFn
 60 | 	ModifierShift
 61 | )
 62 | 
 63 | // KeyCombination represents a key together with zero or more modifiers. It
 64 | // is used to set up keyboard shortcuts.
 65 | type KeyCombination struct {
 66 | 	Key       string
 67 | 	Modifiers Modifier
 68 | }
 69 | 
 70 | var (
 71 | 	errEmptyKey      = errors.New("empty key")
 72 | 	errEmptyShortcut = errors.New("empty shortcut")
 73 | )
 74 | 
 75 | // ParseKeys parses a key combination specified as a string like "cmd shift a".
 76 | func ParseKeys(s string) (KeyCombination, error) {
 77 | 	// for backwards compatibility split on both "+" and " "
 78 | 	parts := strings.Split(s, " ")
 79 | 	if strings.Contains(s, "+") {
 80 | 		parts = strings.Split(s, "+")
 81 | 	}
 82 | 	if len(parts) == 0 {
 83 | 		return KeyCombination{}, errEmptyShortcut
 84 | 	}
 85 | 	var keys KeyCombination
 86 | 	keys.Key = parts[len(parts)-1]
 87 | 	if len(keys.Key) == 0 {
 88 | 		return KeyCombination{}, errEmptyKey
 89 | 	}
 90 | 	for _, part := range parts[:len(parts)-1] {
 91 | 		switch strings.ToLower(part) {
 92 | 		case "cmd":
 93 | 			keys.Modifiers |= ModifierCmd
 94 | 		case "ctrl":
 95 | 			keys.Modifiers |= ModifierCtrl
 96 | 		case "cmdctrl":
 97 | 			keys.Modifiers |= ModifierCmdOrCtrl
 98 | 		case "alt":
 99 | 			keys.Modifiers |= ModifierAltOrOption
100 | 		case "option":
101 | 			keys.Modifiers |= ModifierAltOrOption
102 | 		case "fn":
103 | 			keys.Modifiers |= ModifierFn
104 | 		case "shift":
105 | 			keys.Modifiers |= ModifierShift
106 | 		default:
107 | 			return KeyCombination{}, fmt.Errorf("unknown modifier: %s", part)
108 | 		}
109 | 	}
110 | 	return keys, nil
111 | }
112 | 
113 | // MustParseKeys is like ParseKeys but panics on error
114 | func MustParseKeys(s string) KeyCombination {
115 | 	keys, err := ParseKeys(s)
116 | 	if err != nil {
117 | 		panic(err)
118 | 	}
119 | 	return keys
120 | }
121 | 
122 | // AddGlobalShortcut calls the handler whenever the key combination is pressed
123 | // in any application.
124 | func AddGlobalShortcut(keys KeyCombination, handler func()) {
125 | 	id := nextID
126 | 	nextID++
127 | 	handlers[id] = handler
128 | 
129 | 	C.helper_AddGlobalShortcut(
130 | 		C.int(id),
131 | 		C.CString(keys.Key),
132 | 		C.gallium_modifier_t(keys.Modifiers))
133 | }
134 | 


--------------------------------------------------------------------------------
/linkflags.go:
--------------------------------------------------------------------------------
 1 | package gallium
 2 | 
 3 | /*
 4 | #cgo LDFLAGS: -F${SRCDIR}/dist
 5 | #cgo LDFLAGS: -framework Gallium
 6 | #cgo LDFLAGS: -Wl,-rpath,@executable_path/../Frameworks
 7 | #cgo LDFLAGS: -Wl,-rpath,@loader_path/../Frameworks
 8 | #cgo LDFLAGS: -Wl,-rpath,${SRCDIR}/dist
 9 | #cgo LDFLAGS: -mmacosx-version-min=10.8
10 | */
11 | import "C"
12 | 


--------------------------------------------------------------------------------
/rect.go:
--------------------------------------------------------------------------------
 1 | package gallium
 2 | 
 3 | /*
 4 | #cgo CFLAGS: -mmacosx-version-min=10.8
 5 | #cgo CFLAGS: -DGALLIUM_DIR=${SRCDIR}
 6 | #cgo CFLAGS: -Idist/include
 7 | 
 8 | #include <stdlib.h>
 9 | #include "gallium/core.h"
10 | */
11 | import "C"
12 | 
13 | // Rect represents a rectangular region on the screen
14 | type Rect struct {
15 | 	Width  int // Width in pixels
16 | 	Height int // Height in pixels
17 | 	Left   int // Left is offset from left in pixel
18 | 	Bottom int // Left is offset from top in pixels
19 | }
20 | 
21 | func rectFromC(c C.gallium_rect_t) Rect {
22 | 	return Rect{
23 | 		Width:  int(c.width),
24 | 		Height: int(c.height),
25 | 		Left:   int(c.left),
26 | 		Bottom: int(c.bottom),
27 | 	}
28 | }
29 | 


--------------------------------------------------------------------------------
/redirect.go:
--------------------------------------------------------------------------------
 1 | package gallium
 2 | 
 3 | import (
 4 | 	"os"
 5 | 	"syscall"
 6 | )
 7 | 
 8 | // RedirectStdoutStderr overwrites the stdout and stderr streams with a file
 9 | // descriptor that writes to the given path. This is done with os.Dup2,
10 | // meaning that even C functions that write to stdout or stderr will be
11 | // redirected to the file.
12 | func RedirectStdoutStderr(path string) (*os.File, error) {
13 | 	return redirect(path, os.Stdout.Fd(), os.Stderr.Fd())
14 | }
15 | 
16 | // RedirectStdout overwrites the stdout streams with a file
17 | // descriptor that writes to the given path. This is done with os.Dup2,
18 | // meaning that even C functions that write to stdout will be
19 | // redirected to the file.
20 | func RedirectStdout(path string) (*os.File, error) {
21 | 	return redirect(path, os.Stdout.Fd())
22 | }
23 | 
24 | // RedirectStderr overwrites the stderr streams with a file
25 | // descriptor that writes to the given path. This is done with os.Dup2,
26 | // meaning that even C functions that write to stderr will be
27 | // redirected to the file.
28 | func RedirectStderr(path string) (*os.File, error) {
29 | 	return redirect(path, os.Stderr.Fd())
30 | }
31 | 
32 | func redirect(path string, fds ...uintptr) (*os.File, error) {
33 | 	f, err := os.OpenFile(path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0777)
34 | 	if err != nil {
35 | 		return nil, err
36 | 	}
37 | 
38 | 	for _, fd := range fds {
39 | 		err = syscall.Dup2(int(f.Fd()), int(fd))
40 | 		if err != nil {
41 | 			return nil, err
42 | 		}
43 | 	}
44 | 
45 | 	return f, nil
46 | }
47 | 


--------------------------------------------------------------------------------
/screen.go:
--------------------------------------------------------------------------------
 1 | package gallium
 2 | 
 3 | /*
 4 | #cgo CFLAGS: -mmacosx-version-min=10.8
 5 | #cgo CFLAGS: -DGALLIUM_DIR=${SRCDIR}
 6 | #cgo CFLAGS: -Idist/include
 7 | 
 8 | #include <stdlib.h>
 9 | #include "gallium/screen.h"
10 | */
11 | import "C"
12 | import "fmt"
13 | 
14 | // A screen represents a rectangular display, normally corresponding to a
15 | // physical display. "Device coordinates" means a position on a screen
16 | // measured from (0, 0) at the bottom left of the device. "Global coordinates"
17 | // means the coordinate system in which each of the screens are positioned
18 | // relative to each other. Global and device coordinates almost always have
19 | // the same scale factor. It is possible for screens to overlap in global
20 | // coordinates (such as when mirroring a display.)
21 | type Screen struct {
22 | 	Shape        Rect // the size and position of this screen in global coords
23 | 	Usable       Rect // excludes the menubar and dock
24 | 	BitsPerPixel int  // color depth of this screen (total of all color components)
25 | 	ID           int  // unique identifier for this screen
26 | }
27 | 
28 | func screenFromC(c *C.gallium_screen_t) Screen {
29 | 	return Screen{
30 | 		Shape:        rectFromC(C.GalliumScreenShape(c)),
31 | 		Usable:       rectFromC(C.GalliumScreenUsable(c)),
32 | 		BitsPerPixel: int(C.GalliumScreenBitsPerPixel(c)),
33 | 		ID:           int(C.GalliumScreenID(c)),
34 | 	}
35 | }
36 | 
37 | // Screens gets a list of available screens
38 | func Screens() []Screen {
39 | 	var screens []Screen
40 | 	n := int(C.GalliumScreenCount())
41 | 	for i := 0; i < n; i++ {
42 | 		c := C.GalliumScreen(C.int(i))
43 | 		if c == nil {
44 | 			panic(fmt.Sprintf("GalliumScreen returned nil for index %d", i))
45 | 		}
46 | 		screens = append(screens, screenFromC(c))
47 | 	}
48 | 	return screens
49 | }
50 | 
51 | // FocusedScreen gets the screen containing the currently focused window
52 | func FocusedScreen() Screen {
53 | 	c := C.GalliumFocusedScreen()
54 | 	if c == nil {
55 | 		panic("GalliumFocusedScreen returned nil")
56 | 	}
57 | 	return screenFromC(c)
58 | }
59 | 


--------------------------------------------------------------------------------
/vendor/github.com/alexflint/go-arg/.gitignore:
--------------------------------------------------------------------------------
 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects)
 2 | *.o
 3 | *.a
 4 | *.so
 5 | 
 6 | # Folders
 7 | _obj
 8 | _test
 9 | 
10 | # Architecture specific extensions/prefixes
11 | *.[568vq]
12 | [568vq].out
13 | 
14 | *.cgo1.go
15 | *.cgo2.c
16 | _cgo_defun.c
17 | _cgo_gotypes.go
18 | _cgo_export.*
19 | 
20 | _testmain.go
21 | 
22 | *.exe
23 | *.test
24 | *.prof
25 | 


--------------------------------------------------------------------------------
/vendor/github.com/alexflint/go-arg/.travis.yml:
--------------------------------------------------------------------------------
 1 | language: go
 2 | go:
 3 |   - tip
 4 | before_install:
 5 |   - go get github.com/axw/gocov/gocov
 6 |   - go get github.com/mattn/goveralls
 7 |   - if ! go get github.com/golang/tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi
 8 | script:
 9 |   - $HOME/gopath/bin/goveralls -service=travis-ci
10 | 


--------------------------------------------------------------------------------
/vendor/github.com/alexflint/go-arg/LICENSE:
--------------------------------------------------------------------------------
 1 | Copyright (c) 2015, Alex Flint
 2 | All rights reserved.
 3 | 
 4 | Redistribution and use in source and binary forms, with or without
 5 | modification, are permitted provided that the following conditions are met:
 6 | 
 7 | * Redistributions of source code must retain the above copyright notice, this
 8 |   list of conditions and the following disclaimer.
 9 | 
10 | * Redistributions in binary form must reproduce the above copyright notice,
11 |   this list of conditions and the following disclaimer in the documentation
12 |   and/or other materials provided with the distribution.
13 | 
14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 | 
25 | 


--------------------------------------------------------------------------------
/vendor/github.com/alexflint/go-arg/README.md:
--------------------------------------------------------------------------------
  1 | [![GoDoc](https://godoc.org/github.com/alexflint/go-arg?status.svg)](https://godoc.org/github.com/alexflint/go-arg)
  2 | [![Build Status](https://travis-ci.org/alexflint/go-arg.svg?branch=master)](https://travis-ci.org/alexflint/go-arg)
  3 | [![Coverage Status](https://coveralls.io/repos/alexflint/go-arg/badge.svg?branch=master&service=github)](https://coveralls.io/github/alexflint/go-arg?branch=master)
  4 | [![Report Card](https://goreportcard.com/badge/github.com/alexflint/go-arg)](https://goreportcard.com/badge/github.com/alexflint/go-arg)
  5 | 
  6 | ## Structured argument parsing for Go
  7 | 
  8 | ```shell
  9 | go get github.com/alexflint/go-arg
 10 | ```
 11 | 
 12 | Declare the command line arguments your program accepts by defining a struct.
 13 | 
 14 | ```go
 15 | var args struct {
 16 | 	Foo string
 17 | 	Bar bool
 18 | }
 19 | arg.MustParse(&args)
 20 | fmt.Println(args.Foo, args.Bar)
 21 | ```
 22 | 
 23 | ```shell
 24 | $ ./example --foo=hello --bar
 25 | hello true
 26 | ```
 27 | 
 28 | ### Required arguments
 29 | 
 30 | ```go
 31 | var args struct {
 32 | 	ID      int `arg:"required"`
 33 | 	Timeout time.Duration
 34 | }
 35 | arg.MustParse(&args)
 36 | ```
 37 | 
 38 | ```shell
 39 | $ ./example
 40 | usage: example --id ID [--timeout TIMEOUT]
 41 | error: --id is required
 42 | ```
 43 | 
 44 | ### Positional arguments
 45 | 
 46 | ```go
 47 | var args struct {
 48 | 	Input   string   `arg:"positional"`
 49 | 	Output  []string `arg:"positional"`
 50 | }
 51 | arg.MustParse(&args)
 52 | fmt.Println("Input:", args.Input)
 53 | fmt.Println("Output:", args.Output)
 54 | ```
 55 | 
 56 | ```
 57 | $ ./example src.txt x.out y.out z.out
 58 | Input: src.txt
 59 | Output: [x.out y.out z.out]
 60 | ```
 61 | 
 62 | ### Environment variables
 63 | 
 64 | ```go
 65 | var args struct {
 66 | 	Workers int `arg:"env"`
 67 | }
 68 | arg.MustParse(&args)
 69 | fmt.Println("Workers:", args.Workers)
 70 | ```
 71 | 
 72 | ```
 73 | $ WORKERS=4 ./example
 74 | Workers: 4
 75 | ```
 76 | 
 77 | ```
 78 | $ WORKERS=4 ./example --workers=6
 79 | Workers: 6
 80 | ```
 81 | 
 82 | You can also override the name of the environment variable:
 83 | 
 84 | ```go
 85 | var args struct {
 86 | 	Workers int `arg:"env:NUM_WORKERS"`
 87 | }
 88 | arg.MustParse(&args)
 89 | fmt.Println("Workers:", args.Workers)
 90 | ```
 91 | 
 92 | ```
 93 | $ NUM_WORKERS=4 ./example
 94 | Workers: 4
 95 | ```
 96 | 
 97 | ### Usage strings
 98 | ```go
 99 | var args struct {
100 | 	Input    string   `arg:"positional"`
101 | 	Output   []string `arg:"positional"`
102 | 	Verbose  bool     `arg:"-v,help:verbosity level"`
103 | 	Dataset  string   `arg:"help:dataset to use"`
104 | 	Optimize int      `arg:"-O,help:optimization level"`
105 | }
106 | arg.MustParse(&args)
107 | ```
108 | 
109 | ```shell
110 | $ ./example -h
111 | usage: [--verbose] [--dataset DATASET] [--optimize OPTIMIZE] [--help] INPUT [OUTPUT [OUTPUT ...]] 
112 | 
113 | positional arguments:
114 |   input
115 |   output
116 | 
117 | options:
118 |   --verbose, -v            verbosity level
119 |   --dataset DATASET        dataset to use
120 |   --optimize OPTIMIZE, -O OPTIMIZE
121 |                            optimization level
122 |   --help, -h               print this help message
123 | ```
124 | 
125 | ### Default values
126 | 
127 | ```go
128 | var args struct {
129 | 	Foo string
130 | 	Bar bool
131 | }
132 | args.Foo = "default value"
133 | arg.MustParse(&args)
134 | ```
135 | 
136 | ### Arguments with multiple values
137 | ```go
138 | var args struct {
139 | 	Database string
140 | 	IDs      []int64
141 | }
142 | arg.MustParse(&args)
143 | fmt.Printf("Fetching the following IDs from %s: %q", args.Database, args.IDs)
144 | ```
145 | 
146 | ```shell
147 | ./example -database foo -ids 1 2 3
148 | Fetching the following IDs from foo: [1 2 3]
149 | ```
150 | 
151 | ### Custom validation
152 | ```go
153 | var args struct {
154 | 	Foo string
155 | 	Bar string
156 | }
157 | p := arg.MustParse(&args)
158 | if args.Foo == "" && args.Bar == "" {
159 | 	p.Fail("you must provide one of --foo and --bar")
160 | }
161 | ```
162 | 
163 | ```shell
164 | ./example
165 | usage: samples [--foo FOO] [--bar BAR]
166 | error: you must provide one of --foo and --bar
167 | ```
168 | 
169 | ### Version strings
170 | 
171 | ```go
172 | type args struct {
173 | 	...
174 | }
175 | 
176 | func (args) Version() string {
177 | 	return "someprogram 4.3.0"
178 | }
179 | 
180 | func main() {
181 | 	var args args
182 | 	arg.MustParse(&args)
183 | }
184 | ```
185 | 
186 | ```shell
187 | $ ./example --version
188 | someprogram 4.3.0
189 | ```
190 | 
191 | ### Custom parsing
192 | 
193 | You can implement your own argument parser by implementing `encoding.TextUnmarshaler`:
194 | 
195 | ```go
196 | package main
197 | 
198 | import (
199 | 	"fmt"
200 | 	"strings"
201 | 
202 | 	"github.com/alexflint/go-arg"
203 | )
204 | 
205 | // Accepts command line arguments of the form "head.tail"
206 | type NameDotName struct {
207 | 	Head, Tail string
208 | }
209 | 
210 | func (n *NameDotName) UnmarshalText(b []byte) error {
211 | 	s := string(b)
212 | 	pos := strings.Index(s, ".")
213 | 	if pos == -1 {
214 | 		return fmt.Errorf("missing period in %s", s)
215 | 	}
216 | 	n.Head = s[:pos]
217 | 	n.Tail = s[pos+1:]
218 | 	return nil
219 | }
220 | 
221 | func main() {
222 | 	var args struct {
223 | 		Name *NameDotName
224 | 	}
225 | 	arg.MustParse(&args)
226 | 	fmt.Printf("%#v\n", args.Name)
227 | }
228 | ```
229 | ```shell
230 | $ ./example --name=foo.bar
231 | &main.NameDotName{Head:"foo", Tail:"bar"}
232 | 
233 | $ ./example --name=oops
234 | usage: example [--name NAME]
235 | error: error processing --name: missing period in "oops"
236 | ```
237 | 
238 | ### Documentation
239 | 
240 | https://godoc.org/github.com/alexflint/go-arg
241 | 
242 | ### Rationale
243 | 
244 | There are many command line argument parsing libraries for Go, including one in the standard library, so why build another?
245 | 
246 | The shortcomings of the `flag` library that ships in the standard library are well known. Positional arguments must preceed options, so `./prog x --foo=1` does what you expect but `./prog --foo=1 x` does not. Arguments cannot have both long (`--foo`) and short (`-f`) forms.
247 | 
248 | Many third-party argument parsing libraries are geared for writing sophisticated command line interfaces. The excellent `codegangsta/cli` is perfect for working with multiple sub-commands and nested flags, but is probably overkill for a simple script with a handful of flags.
249 | 
250 | The main idea behind `go-arg` is that Go already has an excellent way to describe data structures using Go structs, so there is no need to develop more levels of abstraction on top of this. Instead of one API to specify which arguments your program accepts, and then another API to get the values of those arguments, why not replace both with a single struct?
251 | 


--------------------------------------------------------------------------------
/vendor/github.com/alexflint/go-arg/doc.go:
--------------------------------------------------------------------------------
 1 | // Package arg parses command line arguments using the fields from a struct.
 2 | //
 3 | // For example,
 4 | //
 5 | //	var args struct {
 6 | //		Iter int
 7 | //		Debug bool
 8 | //	}
 9 | //	arg.MustParse(&args)
10 | //
11 | // defines two command line arguments, which can be set using any of
12 | //
13 | //	./example --iter=1 --debug  // debug is a boolean flag so its value is set to true
14 | //	./example -iter 1           // debug defaults to its zero value (false)
15 | //	./example --debug=true      // iter defaults to its zero value (zero)
16 | //
17 | // The fastest way to see how to use go-arg is to read the examples below.
18 | //
19 | // Fields can be bool, string, any float type, or any signed or unsigned integer type.
20 | // They can also be slices of any of the above, or slices of pointers to any of the above.
21 | //
22 | // Tags can be specified using the `arg` package name:
23 | //
24 | //	var args struct {
25 | //		Input string   `arg:"positional"`
26 | //		Log string     `arg:"positional,required"`
27 | //		Debug bool     `arg:"-d,help:turn on debug mode"`
28 | //		RealMode bool  `arg:"--real"
29 | //		Wr io.Writer   `arg:"-"`
30 | //	}
31 | //
32 | // The valid tag strings are `positional`, `required`, and `help`. Further, any tag string
33 | // that starts with a single hyphen is the short form for an argument (e.g. `./example -d`),
34 | // and any tag string that starts with two hyphens is the long form for the argument
35 | // (instead of the field name). Fields can be excluded from processing with `arg:"-"`.
36 | package arg
37 | 


--------------------------------------------------------------------------------
/vendor/github.com/alexflint/go-arg/parse.go:
--------------------------------------------------------------------------------
  1 | package arg
  2 | 
  3 | import (
  4 | 	"errors"
  5 | 	"fmt"
  6 | 	"os"
  7 | 	"path/filepath"
  8 | 	"reflect"
  9 | 	"strings"
 10 | )
 11 | 
 12 | // spec represents a command line option
 13 | type spec struct {
 14 | 	dest       reflect.Value
 15 | 	long       string
 16 | 	short      string
 17 | 	multiple   bool
 18 | 	required   bool
 19 | 	positional bool
 20 | 	help       string
 21 | 	env        string
 22 | 	wasPresent bool
 23 | 	boolean    bool
 24 | 	fieldName  string // for generating helpful errors
 25 | }
 26 | 
 27 | // ErrHelp indicates that -h or --help were provided
 28 | var ErrHelp = errors.New("help requested by user")
 29 | 
 30 | // ErrVersion indicates that --version was provided
 31 | var ErrVersion = errors.New("version requested by user")
 32 | 
 33 | // MustParse processes command line arguments and exits upon failure
 34 | func MustParse(dest ...interface{}) *Parser {
 35 | 	p, err := NewParser(Config{}, dest...)
 36 | 	if err != nil {
 37 | 		fmt.Println(err)
 38 | 		os.Exit(-1)
 39 | 	}
 40 | 	err = p.Parse(os.Args[1:])
 41 | 	if err == ErrHelp {
 42 | 		p.WriteHelp(os.Stdout)
 43 | 		os.Exit(0)
 44 | 	}
 45 | 	if err == ErrVersion {
 46 | 		fmt.Println(p.version)
 47 | 		os.Exit(0)
 48 | 	}
 49 | 	if err != nil {
 50 | 		p.Fail(err.Error())
 51 | 	}
 52 | 	return p
 53 | }
 54 | 
 55 | // Parse processes command line arguments and stores them in dest
 56 | func Parse(dest ...interface{}) error {
 57 | 	p, err := NewParser(Config{}, dest...)
 58 | 	if err != nil {
 59 | 		return err
 60 | 	}
 61 | 	return p.Parse(os.Args[1:])
 62 | }
 63 | 
 64 | // Config represents configuration options for an argument parser
 65 | type Config struct {
 66 | 	Program string // Program is the name of the program used in the help text
 67 | }
 68 | 
 69 | // Parser represents a set of command line options with destination values
 70 | type Parser struct {
 71 | 	spec    []*spec
 72 | 	config  Config
 73 | 	version string
 74 | }
 75 | 
 76 | // Versioned is the interface that the destination struct should implement to
 77 | // make a version string appear at the top of the help message.
 78 | type Versioned interface {
 79 | 	// Version returns the version string that will be printed on a line by itself
 80 | 	// at the top of the help message.
 81 | 	Version() string
 82 | }
 83 | 
 84 | // NewParser constructs a parser from a list of destination structs
 85 | func NewParser(config Config, dests ...interface{}) (*Parser, error) {
 86 | 	p := Parser{
 87 | 		config: config,
 88 | 	}
 89 | 	for _, dest := range dests {
 90 | 		if dest, ok := dest.(Versioned); ok {
 91 | 			p.version = dest.Version()
 92 | 		}
 93 | 		v := reflect.ValueOf(dest)
 94 | 		if v.Kind() != reflect.Ptr {
 95 | 			panic(fmt.Sprintf("%s is not a pointer (did you forget an ampersand?)", v.Type()))
 96 | 		}
 97 | 		v = v.Elem()
 98 | 		if v.Kind() != reflect.Struct {
 99 | 			panic(fmt.Sprintf("%T is not a struct pointer", dest))
100 | 		}
101 | 
102 | 		t := v.Type()
103 | 		for i := 0; i < t.NumField(); i++ {
104 | 			// Check for the ignore switch in the tag
105 | 			field := t.Field(i)
106 | 			tag := field.Tag.Get("arg")
107 | 			if tag == "-" {
108 | 				continue
109 | 			}
110 | 
111 | 			spec := spec{
112 | 				long:      strings.ToLower(field.Name),
113 | 				dest:      v.Field(i),
114 | 				fieldName: t.Name() + "." + field.Name,
115 | 			}
116 | 
117 | 			// Check whether this field is supported. It's good to do this here rather than
118 | 			// wait until setScalar because it means that a program with invalid argument
119 | 			// fields will always fail regardless of whether the arguments it received
120 | 			// exercised those fields.
121 | 			var parseable bool
122 | 			parseable, spec.boolean, spec.multiple = canParse(field.Type)
123 | 			if !parseable {
124 | 				return nil, fmt.Errorf("%s.%s: %s fields are not supported", t.Name(), field.Name, field.Type.String())
125 | 			}
126 | 
127 | 			// Look at the tag
128 | 			if tag != "" {
129 | 				for _, key := range strings.Split(tag, ",") {
130 | 					var value string
131 | 					if pos := strings.Index(key, ":"); pos != -1 {
132 | 						value = key[pos+1:]
133 | 						key = key[:pos]
134 | 					}
135 | 
136 | 					switch {
137 | 					case strings.HasPrefix(key, "--"):
138 | 						spec.long = key[2:]
139 | 					case strings.HasPrefix(key, "-"):
140 | 						if len(key) != 2 {
141 | 							return nil, fmt.Errorf("%s.%s: short arguments must be one character only", t.Name(), field.Name)
142 | 						}
143 | 						spec.short = key[1:]
144 | 					case key == "required":
145 | 						spec.required = true
146 | 					case key == "positional":
147 | 						spec.positional = true
148 | 					case key == "help":
149 | 						spec.help = value
150 | 					case key == "env":
151 | 						// Use override name if provided
152 | 						if value != "" {
153 | 							spec.env = value
154 | 						} else {
155 | 							spec.env = strings.ToUpper(field.Name)
156 | 						}
157 | 					default:
158 | 						return nil, fmt.Errorf("unrecognized tag '%s' on field %s", key, tag)
159 | 					}
160 | 				}
161 | 			}
162 | 			p.spec = append(p.spec, &spec)
163 | 		}
164 | 	}
165 | 	if p.config.Program == "" {
166 | 		p.config.Program = "program"
167 | 		if len(os.Args) > 0 {
168 | 			p.config.Program = filepath.Base(os.Args[0])
169 | 		}
170 | 	}
171 | 	return &p, nil
172 | }
173 | 
174 | // Parse processes the given command line option, storing the results in the field
175 | // of the structs from which NewParser was constructed
176 | func (p *Parser) Parse(args []string) error {
177 | 	// If -h or --help were specified then print usage
178 | 	for _, arg := range args {
179 | 		if arg == "-h" || arg == "--help" {
180 | 			return ErrHelp
181 | 		}
182 | 		if arg == "--version" {
183 | 			return ErrVersion
184 | 		}
185 | 		if arg == "--" {
186 | 			break
187 | 		}
188 | 	}
189 | 
190 | 	// Process all command line arguments
191 | 	err := process(p.spec, args)
192 | 	if err != nil {
193 | 		return err
194 | 	}
195 | 
196 | 	// Validate
197 | 	return validate(p.spec)
198 | }
199 | 
200 | // process goes through arguments one-by-one, parses them, and assigns the result to
201 | // the underlying struct field
202 | func process(specs []*spec, args []string) error {
203 | 	// construct a map from --option to spec
204 | 	optionMap := make(map[string]*spec)
205 | 	for _, spec := range specs {
206 | 		if spec.positional {
207 | 			continue
208 | 		}
209 | 		if spec.long != "" {
210 | 			optionMap[spec.long] = spec
211 | 		}
212 | 		if spec.short != "" {
213 | 			optionMap[spec.short] = spec
214 | 		}
215 | 		if spec.env != "" {
216 | 			if value, found := os.LookupEnv(spec.env); found {
217 | 				err := setScalar(spec.dest, value)
218 | 				if err != nil {
219 | 					return fmt.Errorf("error processing environment variable %s: %v", spec.env, err)
220 | 				}
221 | 				spec.wasPresent = true
222 | 			}
223 | 		}
224 | 	}
225 | 
226 | 	// process each string from the command line
227 | 	var allpositional bool
228 | 	var positionals []string
229 | 
230 | 	// must use explicit for loop, not range, because we manipulate i inside the loop
231 | 	for i := 0; i < len(args); i++ {
232 | 		arg := args[i]
233 | 		if arg == "--" {
234 | 			allpositional = true
235 | 			continue
236 | 		}
237 | 
238 | 		if !strings.HasPrefix(arg, "-") || allpositional {
239 | 			positionals = append(positionals, arg)
240 | 			continue
241 | 		}
242 | 
243 | 		// check for an equals sign, as in "--foo=bar"
244 | 		var value string
245 | 		opt := strings.TrimLeft(arg, "-")
246 | 		if pos := strings.Index(opt, "="); pos != -1 {
247 | 			value = opt[pos+1:]
248 | 			opt = opt[:pos]
249 | 		}
250 | 
251 | 		// lookup the spec for this option
252 | 		spec, ok := optionMap[opt]
253 | 		if !ok {
254 | 			return fmt.Errorf("unknown argument %s", arg)
255 | 		}
256 | 		spec.wasPresent = true
257 | 
258 | 		// deal with the case of multiple values
259 | 		if spec.multiple {
260 | 			var values []string
261 | 			if value == "" {
262 | 				for i+1 < len(args) && !strings.HasPrefix(args[i+1], "-") {
263 | 					values = append(values, args[i+1])
264 | 					i++
265 | 				}
266 | 			} else {
267 | 				values = append(values, value)
268 | 			}
269 | 			err := setSlice(spec.dest, values)
270 | 			if err != nil {
271 | 				return fmt.Errorf("error processing %s: %v", arg, err)
272 | 			}
273 | 			continue
274 | 		}
275 | 
276 | 		// if it's a flag and it has no value then set the value to true
277 | 		// use boolean because this takes account of TextUnmarshaler
278 | 		if spec.boolean && value == "" {
279 | 			value = "true"
280 | 		}
281 | 
282 | 		// if we have something like "--foo" then the value is the next argument
283 | 		if value == "" {
284 | 			if i+1 == len(args) || strings.HasPrefix(args[i+1], "-") {
285 | 				return fmt.Errorf("missing value for %s", arg)
286 | 			}
287 | 			value = args[i+1]
288 | 			i++
289 | 		}
290 | 
291 | 		err := setScalar(spec.dest, value)
292 | 		if err != nil {
293 | 			return fmt.Errorf("error processing %s: %v", arg, err)
294 | 		}
295 | 	}
296 | 
297 | 	// process positionals
298 | 	for _, spec := range specs {
299 | 		if spec.positional {
300 | 			if spec.multiple {
301 | 				err := setSlice(spec.dest, positionals)
302 | 				if err != nil {
303 | 					return fmt.Errorf("error processing %s: %v", spec.long, err)
304 | 				}
305 | 				positionals = nil
306 | 			} else if len(positionals) > 0 {
307 | 				err := setScalar(spec.dest, positionals[0])
308 | 				if err != nil {
309 | 					return fmt.Errorf("error processing %s: %v", spec.long, err)
310 | 				}
311 | 				positionals = positionals[1:]
312 | 			} else if spec.required {
313 | 				return fmt.Errorf("%s is required", spec.long)
314 | 			}
315 | 		}
316 | 	}
317 | 	if len(positionals) > 0 {
318 | 		return fmt.Errorf("too many positional arguments at '%s'", positionals[0])
319 | 	}
320 | 	return nil
321 | }
322 | 
323 | // validate an argument spec after arguments have been parse
324 | func validate(spec []*spec) error {
325 | 	for _, arg := range spec {
326 | 		if !arg.positional && arg.required && !arg.wasPresent {
327 | 			return fmt.Errorf("--%s is required", arg.long)
328 | 		}
329 | 	}
330 | 	return nil
331 | }
332 | 
333 | // parse a value as the appropriate type and store it in the struct
334 | func setSlice(dest reflect.Value, values []string) error {
335 | 	if !dest.CanSet() {
336 | 		return fmt.Errorf("field is not writable")
337 | 	}
338 | 
339 | 	var ptr bool
340 | 	elem := dest.Type().Elem()
341 | 	if elem.Kind() == reflect.Ptr {
342 | 		ptr = true
343 | 		elem = elem.Elem()
344 | 	}
345 | 
346 | 	// Truncate the dest slice in case default values exist
347 | 	if !dest.IsNil() {
348 | 		dest.SetLen(0)
349 | 	}
350 | 
351 | 	for _, s := range values {
352 | 		v := reflect.New(elem)
353 | 		if err := setScalar(v.Elem(), s); err != nil {
354 | 			return err
355 | 		}
356 | 		if !ptr {
357 | 			v = v.Elem()
358 | 		}
359 | 		dest.Set(reflect.Append(dest, v))
360 | 	}
361 | 	return nil
362 | }
363 | 
364 | // canParse returns true if the type can be parsed from a string
365 | func canParse(t reflect.Type) (parseable, boolean, multiple bool) {
366 | 	parseable, boolean = isScalar(t)
367 | 	if parseable {
368 | 		return
369 | 	}
370 | 
371 | 	// Look inside pointer types
372 | 	if t.Kind() == reflect.Ptr {
373 | 		t = t.Elem()
374 | 	}
375 | 	// Look inside slice types
376 | 	if t.Kind() == reflect.Slice {
377 | 		multiple = true
378 | 		t = t.Elem()
379 | 	}
380 | 
381 | 	parseable, boolean = isScalar(t)
382 | 	if parseable {
383 | 		return
384 | 	}
385 | 
386 | 	// Look inside pointer types (again, in case of []*Type)
387 | 	if t.Kind() == reflect.Ptr {
388 | 		t = t.Elem()
389 | 	}
390 | 
391 | 	parseable, boolean = isScalar(t)
392 | 	if parseable {
393 | 		return
394 | 	}
395 | 
396 | 	return false, false, false
397 | }
398 | 


--------------------------------------------------------------------------------
/vendor/github.com/alexflint/go-arg/scalar.go:
--------------------------------------------------------------------------------
  1 | package arg
  2 | 
  3 | import (
  4 | 	"encoding"
  5 | 	"fmt"
  6 | 	"net"
  7 | 	"net/mail"
  8 | 	"reflect"
  9 | 	"strconv"
 10 | 	"time"
 11 | )
 12 | 
 13 | // The reflected form of some special types
 14 | var (
 15 | 	textUnmarshalerType = reflect.TypeOf([]encoding.TextUnmarshaler{}).Elem()
 16 | 	durationType        = reflect.TypeOf(time.Duration(0))
 17 | 	mailAddressType     = reflect.TypeOf(mail.Address{})
 18 | 	ipType              = reflect.TypeOf(net.IP{})
 19 | 	macType             = reflect.TypeOf(net.HardwareAddr{})
 20 | )
 21 | 
 22 | // isScalar returns true if the type can be parsed from a single string
 23 | func isScalar(t reflect.Type) (scalar, boolean bool) {
 24 | 	// If it implements encoding.TextUnmarshaler then use that
 25 | 	if t.Implements(textUnmarshalerType) {
 26 | 		// scalar=YES, boolean=NO
 27 | 		return true, false
 28 | 	}
 29 | 
 30 | 	// If we have a pointer then dereference it
 31 | 	if t.Kind() == reflect.Ptr {
 32 | 		t = t.Elem()
 33 | 	}
 34 | 
 35 | 	// Check for other special types
 36 | 	switch t {
 37 | 	case durationType, mailAddressType, ipType, macType:
 38 | 		// scalar=YES, boolean=NO
 39 | 		return true, false
 40 | 	}
 41 | 
 42 | 	// Fall back to checking the kind
 43 | 	switch t.Kind() {
 44 | 	case reflect.Bool:
 45 | 		// scalar=YES, boolean=YES
 46 | 		return true, true
 47 | 	case reflect.String, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
 48 | 		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
 49 | 		reflect.Float32, reflect.Float64:
 50 | 		// scalar=YES, boolean=NO
 51 | 		return true, false
 52 | 	}
 53 | 	// scalar=NO, boolean=NO
 54 | 	return false, false
 55 | }
 56 | 
 57 | // set a value from a string
 58 | func setScalar(v reflect.Value, s string) error {
 59 | 	if !v.CanSet() {
 60 | 		return fmt.Errorf("field is not exported")
 61 | 	}
 62 | 
 63 | 	// If we have a nil pointer then allocate a new object
 64 | 	if v.Kind() == reflect.Ptr && v.IsNil() {
 65 | 		v.Set(reflect.New(v.Type().Elem()))
 66 | 	}
 67 | 
 68 | 	// Get the object as an interface
 69 | 	scalar := v.Interface()
 70 | 
 71 | 	// If it implements encoding.TextUnmarshaler then use that
 72 | 	if scalar, ok := scalar.(encoding.TextUnmarshaler); ok {
 73 | 		return scalar.UnmarshalText([]byte(s))
 74 | 	}
 75 | 
 76 | 	// If we have a pointer then dereference it
 77 | 	if v.Kind() == reflect.Ptr {
 78 | 		v = v.Elem()
 79 | 	}
 80 | 
 81 | 	// Switch on concrete type
 82 | 	switch scalar.(type) {
 83 | 	case time.Duration:
 84 | 		duration, err := time.ParseDuration(s)
 85 | 		if err != nil {
 86 | 			return err
 87 | 		}
 88 | 		v.Set(reflect.ValueOf(duration))
 89 | 		return nil
 90 | 	case mail.Address:
 91 | 		addr, err := mail.ParseAddress(s)
 92 | 		if err != nil {
 93 | 			return err
 94 | 		}
 95 | 		v.Set(reflect.ValueOf(*addr))
 96 | 		return nil
 97 | 	case net.IP:
 98 | 		ip := net.ParseIP(s)
 99 | 		if ip == nil {
100 | 			return fmt.Errorf(`invalid IP address: "%s"`, s)
101 | 		}
102 | 		v.Set(reflect.ValueOf(ip))
103 | 		return nil
104 | 	case net.HardwareAddr:
105 | 		ip, err := net.ParseMAC(s)
106 | 		if err != nil {
107 | 			return err
108 | 		}
109 | 		v.Set(reflect.ValueOf(ip))
110 | 		return nil
111 | 	}
112 | 
113 | 	// Switch on kind so that we can handle derived types
114 | 	switch v.Kind() {
115 | 	case reflect.String:
116 | 		v.SetString(s)
117 | 	case reflect.Bool:
118 | 		x, err := strconv.ParseBool(s)
119 | 		if err != nil {
120 | 			return err
121 | 		}
122 | 		v.SetBool(x)
123 | 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
124 | 		x, err := strconv.ParseInt(s, 10, v.Type().Bits())
125 | 		if err != nil {
126 | 			return err
127 | 		}
128 | 		v.SetInt(x)
129 | 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
130 | 		x, err := strconv.ParseUint(s, 10, v.Type().Bits())
131 | 		if err != nil {
132 | 			return err
133 | 		}
134 | 		v.SetUint(x)
135 | 	case reflect.Float32, reflect.Float64:
136 | 		x, err := strconv.ParseFloat(s, v.Type().Bits())
137 | 		if err != nil {
138 | 			return err
139 | 		}
140 | 		v.SetFloat(x)
141 | 	default:
142 | 		return fmt.Errorf("cannot parse argument into %s", v.Type().String())
143 | 	}
144 | 	return nil
145 | }
146 | 


--------------------------------------------------------------------------------
/vendor/github.com/alexflint/go-arg/usage.go:
--------------------------------------------------------------------------------
  1 | package arg
  2 | 
  3 | import (
  4 | 	"fmt"
  5 | 	"io"
  6 | 	"os"
  7 | 	"reflect"
  8 | 	"strings"
  9 | )
 10 | 
 11 | // the width of the left column
 12 | const colWidth = 25
 13 | 
 14 | // Fail prints usage information to stderr and exits with non-zero status
 15 | func (p *Parser) Fail(msg string) {
 16 | 	p.WriteUsage(os.Stderr)
 17 | 	fmt.Fprintln(os.Stderr, "error:", msg)
 18 | 	os.Exit(-1)
 19 | }
 20 | 
 21 | // WriteUsage writes usage information to the given writer
 22 | func (p *Parser) WriteUsage(w io.Writer) {
 23 | 	var positionals, options []*spec
 24 | 	for _, spec := range p.spec {
 25 | 		if spec.positional {
 26 | 			positionals = append(positionals, spec)
 27 | 		} else {
 28 | 			options = append(options, spec)
 29 | 		}
 30 | 	}
 31 | 
 32 | 	if p.version != "" {
 33 | 		fmt.Fprintln(w, p.version)
 34 | 	}
 35 | 
 36 | 	fmt.Fprintf(w, "usage: %s", p.config.Program)
 37 | 
 38 | 	// write the option component of the usage message
 39 | 	for _, spec := range options {
 40 | 		// prefix with a space
 41 | 		fmt.Fprint(w, " ")
 42 | 		if !spec.required {
 43 | 			fmt.Fprint(w, "[")
 44 | 		}
 45 | 		fmt.Fprint(w, synopsis(spec, "--"+spec.long))
 46 | 		if !spec.required {
 47 | 			fmt.Fprint(w, "]")
 48 | 		}
 49 | 	}
 50 | 
 51 | 	// write the positional component of the usage message
 52 | 	for _, spec := range positionals {
 53 | 		// prefix with a space
 54 | 		fmt.Fprint(w, " ")
 55 | 		up := strings.ToUpper(spec.long)
 56 | 		if spec.multiple {
 57 | 			fmt.Fprintf(w, "[%s [%s ...]]", up, up)
 58 | 		} else {
 59 | 			fmt.Fprint(w, up)
 60 | 		}
 61 | 	}
 62 | 	fmt.Fprint(w, "\n")
 63 | }
 64 | 
 65 | // WriteHelp writes the usage string followed by the full help string for each option
 66 | func (p *Parser) WriteHelp(w io.Writer) {
 67 | 	var positionals, options []*spec
 68 | 	for _, spec := range p.spec {
 69 | 		if spec.positional {
 70 | 			positionals = append(positionals, spec)
 71 | 		} else {
 72 | 			options = append(options, spec)
 73 | 		}
 74 | 	}
 75 | 
 76 | 	p.WriteUsage(w)
 77 | 
 78 | 	// write the list of positionals
 79 | 	if len(positionals) > 0 {
 80 | 		fmt.Fprint(w, "\npositional arguments:\n")
 81 | 		for _, spec := range positionals {
 82 | 			left := "  " + spec.long
 83 | 			fmt.Fprint(w, left)
 84 | 			if spec.help != "" {
 85 | 				if len(left)+2 < colWidth {
 86 | 					fmt.Fprint(w, strings.Repeat(" ", colWidth-len(left)))
 87 | 				} else {
 88 | 					fmt.Fprint(w, "\n"+strings.Repeat(" ", colWidth))
 89 | 				}
 90 | 				fmt.Fprint(w, spec.help)
 91 | 			}
 92 | 			fmt.Fprint(w, "\n")
 93 | 		}
 94 | 	}
 95 | 
 96 | 	// write the list of options
 97 | 	fmt.Fprint(w, "\noptions:\n")
 98 | 	for _, spec := range options {
 99 | 		printOption(w, spec)
100 | 	}
101 | 
102 | 	// write the list of built in options
103 | 	printOption(w, &spec{boolean: true, long: "help", short: "h", help: "display this help and exit"})
104 | 	if p.version != "" {
105 | 		printOption(w, &spec{boolean: true, long: "version", help: "display version and exit"})
106 | 	}
107 | }
108 | 
109 | func printOption(w io.Writer, spec *spec) {
110 | 	left := "  " + synopsis(spec, "--"+spec.long)
111 | 	if spec.short != "" {
112 | 		left += ", " + synopsis(spec, "-"+spec.short)
113 | 	}
114 | 	fmt.Fprint(w, left)
115 | 	if spec.help != "" {
116 | 		if len(left)+2 < colWidth {
117 | 			fmt.Fprint(w, strings.Repeat(" ", colWidth-len(left)))
118 | 		} else {
119 | 			fmt.Fprint(w, "\n"+strings.Repeat(" ", colWidth))
120 | 		}
121 | 		fmt.Fprint(w, spec.help)
122 | 	}
123 | 	// If spec.dest is not the zero value then a default value has been added.
124 | 	v := spec.dest
125 | 	if v.IsValid() {
126 | 		z := reflect.Zero(v.Type())
127 | 		if (v.Type().Comparable() && z.Type().Comparable() && v.Interface() != z.Interface()) || v.Kind() == reflect.Slice && !v.IsNil() {
128 | 			fmt.Fprintf(w, " [default: %v]", v)
129 | 		}
130 | 	}
131 | 	fmt.Fprint(w, "\n")
132 | }
133 | 
134 | func synopsis(spec *spec, form string) string {
135 | 	if spec.boolean {
136 | 		return form
137 | 	}
138 | 	return form + " " + strings.ToUpper(spec.long)
139 | }
140 | 


--------------------------------------------------------------------------------