<commit_before>// Copyright 2014 Hajime Hoshi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package ebiten

import (
	"sync/atomic"

	"github.com/hajimehoshi/ebiten/v2/internal/clock"
	"github.com/hajimehoshi/ebiten/v2/internal/driver"
)

// Game defines necessary functions for a game.
type Game interface {
	// Update updates a game by one tick. The given argument represents a screen image.
	//
	// Update updates only the game logic and Draw draws the screen.
	//
	// In the first frame, it is ensured that Update is called at least once before Draw. You can use Update
	// to initialize the game state.
	//
	// After the first frame, Update might not be called or might be called once
	// or more for one frame. The frequency is determined by the current TPS (tick-per-second).
	Update() error

	// Draw draws the game screen by one frame.
	//
	// The give argument represents a screen image. The updated content is adopted as the game screen.
	Draw(screen *Image)

	// Layout accepts a native outside size in device-independent pixels and returns the game's logical screen
	// size.
	//
	// On desktops, the outside is a window or a monitor (fullscreen mode). On browsers, the outside is a body
	// element. On mobiles, the outside is the view's size.
	//
	// Even though the outside size and the screen size differ, the rendering scale is automatically adjusted to
	// fit with the outside.
	//
	// Layout is called almost every frame.
	//
	// It is ensured that Layout is invoked before Update is called in the first frame.
	//
	// If Layout returns non-positive numbers, the caller can panic.
	//
	// You can return a fixed screen size if you don't care, or you can also return a calculated screen size
	// adjusted with the given outside size.
	Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int)
}

// DefaultTPS represents a default ticks per second, that represents how many times game updating happens in a second.
const DefaultTPS = 60

// CurrentFPS returns the current number of FPS (frames per second), that represents
// how many swapping buffer happens per second.
//
// On some environments, CurrentFPS doesn't return a reliable value since vsync doesn't work well there.
// If you want to measure the application's speed, Use CurrentTPS.
//
// CurrentFPS is concurrent-safe.
func CurrentFPS() float64 {
	return clock.CurrentFPS()
}

var (
	isScreenClearedEveryFrame = int32(1)
	isRunGameEnded_           = int32(0)
	currentMaxTPS             = int32(DefaultTPS)
)

// SetScreenClearedEveryFrame enables or disables the clearing of the screen at the beginning of each frame.
// The default value is true and the screen is cleared each frame by default.
//
// SetScreenClearedEveryFrame is concurrent-safe.
func SetScreenClearedEveryFrame(cleared bool) {
	v := int32(0)
	if cleared {
		v = 1
	}
	atomic.StoreInt32(&isScreenClearedEveryFrame, v)
	theUIContext.setScreenClearedEveryFrame(cleared)
}

// IsScreenClearedEveryFrame returns true if the frame isn't cleared at the beginning.
//
// IsScreenClearedEveryFrame is concurrent-safe.
func IsScreenClearedEveryFrame() bool {
	return atomic.LoadInt32(&isScreenClearedEveryFrame) != 0
}

type imageDumperGame struct {
	game Game
	d    *imageDumper
	err  error
}

func (i *imageDumperGame) Update() error {
	if i.err != nil {
		return i.err
	}
	if i.d == nil {
		i.d = &imageDumper{g: i.game}
	}
	return i.d.update()
}

func (i *imageDumperGame) Draw(screen *Image) {
	if i.err != nil {
		return
	}

	i.game.Draw(screen)
	i.err = i.d.dump(screen)
}

func (i *imageDumperGame) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) {
	return i.game.Layout(outsideWidth, outsideHeight)
}

// RunGame starts the main loop and runs the game.
// game's Update function is called every tick to update the game logic.
// game's Draw function is, if it exists, called every frame to draw the screen.
// game's Layout function is called when necessary, and you can specify the logical screen size by the function.
//
// game must implement Game interface.
// Game's Draw function is optional, but it is recommended to implement Draw to seperate updating the logic and
// rendering.
//
// RunGame is a more flexibile form of Run due to game's Layout function.
// You can make a resizable window if you use RunGame, while you cannot if you use Run.
// RunGame is more sophisticated way than Run and hides the notion of 'scale'.
//
// While Run specifies the window size, RunGame does not.
// You need to call SetWindowSize before RunGame if you want.
// Otherwise, a default window size is adopted.
//
// Some functions (ScreenScale, SetScreenScale, SetScreenSize) are not available with RunGame.
//
// On browsers, it is strongly recommended to use iframe if you embed an Ebiten application in your website.
//
// RunGame must be called on the main thread.
// Note that Ebiten bounds the main goroutine to the main OS thread by runtime.LockOSThread.
//
// Ebiten tries to call game's Update function 60 times a second by default. In other words,
// TPS (ticks per second) is 60 by default.
// This is not related to framerate (display's refresh rate).
//
// RunGame returns error when 1) error happens in the underlying graphics driver, 2) audio error happens or
// 3) f returns error. In the case of 3), RunGame returns the same error.
//
// The size unit is device-independent pixel.
//
// Don't call RunGame twice or more in one process.
func RunGame(game Game) error {
	defer atomic.StoreInt32(&isRunGameEnded_, 1)

	initializeWindowPositionIfNeeded(WindowSize())
	theUIContext.set(&imageDumperGame{
		game: game,
	})
	if err := uiDriver().Run(theUIContext); err != nil {
		if err == driver.RegularTermination {
			return nil
		}
		return err
	}
	return nil
}

func isRunGameEnded() bool {
	return atomic.LoadInt32(&isRunGameEnded_) != 0
}

// ScreenSizeInFullscreen returns the size in device-independent pixels when the game is fullscreen.
// The adopted monitor is the 'current' monitor which the window belongs to.
// The returned value can be given to Run or SetSize function if the perfectly fit fullscreen is needed.
//
// On browsers, ScreenSizeInFullscreen returns the 'window' (global object) size, not 'screen' size since an Ebiten
// game should not know the outside of the window object.
//
// On mobiles, ScreenSizeInFullscreen returns (0, 0) so far.
//
// ScreenSizeInFullscreen's use cases are limited. If you are making a fullscreen application, you can use RunGame and
// the Game interface's Layout function instead. If you are making a not-fullscreen application but the application's
// behavior depends on the monitor size, ScreenSizeInFullscreen is useful.
//
// ScreenSizeInFullscreen must be called on the main thread before ebiten.Run, and is concurrent-safe after
// ebiten.Run.
func ScreenSizeInFullscreen() (int, int) {
	return uiDriver().ScreenSizeInFullscreen()
}

// CursorMode returns the current cursor mode.
//
// CursorMode returns CursorModeHidden on mobiles.
//
// CursorMode is concurrent-safe.
func CursorMode() CursorModeType {
	return CursorModeType(uiDriver().CursorMode())
}

// SetCursorMode sets the render and capture mode of the mouse cursor.
// CursorModeVisible sets the cursor to always be visible.
// CursorModeHidden hides the system cursor when over the window.
// CursorModeCaptured hides the system cursor and locks it to the window.
//
// CursorModeCaptured also works on browsers.
// When the user exits the captured mode not by SetCursorMode but by the UI (e.g., pressing ESC),
// the previous cursor mode is set automatically.
//
// SetCursorMode does nothing on mobiles.
//
// SetCursorMode is concurrent-safe.
func SetCursorMode(mode CursorModeType) {
	uiDriver().SetCursorMode(driver.CursorMode(mode))
}

func CursorShape() CursorShapeType {
	return CursorShapeType(uiDriver().CursorShape())
}

func SetCursorShape(shape CursorShapeType) {
	uiDriver().SetCursorShape(driver.CursorShape(shape))
}

// IsFullscreen reports whether the current mode is fullscreen or not.
//
// IsFullscreen always returns false on mobiles.
//
// IsFullscreen is concurrent-safe.
func IsFullscreen() bool {
	return uiDriver().IsFullscreen()
}

// SetFullscreen changes the current mode to fullscreen or not on desktops and browsers.
//
// In fullscreen mode, the game screen is automatically enlarged
// to fit with the monitor. The current scale value is ignored.
//
// On desktops, Ebiten uses 'windowed' fullscreen mode, which doesn't change
// your monitor's resolution.
//
// On browsers, triggering fullscreen requires a user gesture otherwise SetFullscreen does nothing but leave an error message in console.
// This behaviour varies across browser implementations, your mileage may vary.
//
// SetFullscreen does nothing on mobiles.
//
// SetFullscreen does nothing on macOS when the window is fullscreened natively by the macOS desktop
// instead of SetFullscreen(true).
//
// SetFullscreen is concurrent-safe.
func SetFullscreen(fullscreen bool) {
	uiDriver().SetFullscreen(fullscreen)
}

// IsFocused returns a boolean value indicating whether
// the game is in focus or in the foreground.
//
// IsFocused will only return true if IsRunnableOnUnfocused is false.
//
// IsFocused is concurrent-safe.
func IsFocused() bool {
	return uiDriver().IsFocused()
}

// IsRunnableOnUnfocused returns a boolean value indicating whether
// the game runs even in background.
//
// IsRunnableOnUnfocused is concurrent-safe.
func IsRunnableOnUnfocused() bool {
	return uiDriver().IsRunnableOnUnfocused()
}

// SetRunnableOnUnfocused sets the state if the game runs even in background.
//
// If the given value is true, the game runs even in background e.g. when losing focus.
// The initial state is true.
//
// Known issue: On browsers, even if the state is on, the game doesn't run in background tabs.
// This is because browsers throttles background tabs not to often update.
//
// SetRunnableOnUnfocused does nothing on mobiles so far.
//
// SetRunnableOnUnfocused is concurrent-safe.
func SetRunnableOnUnfocused(runnableOnUnfocused bool) {
	uiDriver().SetRunnableOnUnfocused(runnableOnUnfocused)
}

// DeviceScaleFactor returns a device scale factor value of the current monitor which the window belongs to.
//
// DeviceScaleFactor returns a meaningful value on high-DPI display environment,
// otherwise DeviceScaleFactor returns 1.
//
// DeviceScaleFactor might panic on init function on some devices like Android.
// Then, it is not recommended to call DeviceScaleFactor from init functions.
//
// DeviceScaleFactor must be called on the main thread before the main loop, and is concurrent-safe after the main
// loop.
//
// DeviceScaleFactor is concurrent-safe.
//
// BUG: DeviceScaleFactor value is not affected by SetWindowPosition before RunGame (#1575).
func DeviceScaleFactor() float64 {
	return uiDriver().DeviceScaleFactor()
}

// IsVsyncEnabled returns a boolean value indicating whether
// the game uses the display's vsync.
//
// IsVsyncEnabled is concurrent-safe.
func IsVsyncEnabled() bool {
	return uiDriver().IsVsyncEnabled()
}

// SetVsyncEnabled sets a boolean value indicating whether
// the game uses the display's vsync.
//
// If the given value is true, the game tries to sync the display's refresh rate.
// If false, the game ignores the display's refresh rate.
// The initial value is true.
// By disabling vsync, the game works more efficiently but consumes more CPU.
//
// Note that the state doesn't affect TPS (ticks per second, i.e. how many the run function is
// updated per second).
//
// SetVsyncEnabled does nothing on mobiles so far.
//
// SetVsyncEnabled is concurrent-safe.
func SetVsyncEnabled(enabled bool) {
	uiDriver().SetVsyncEnabled(enabled)
}

// MaxTPS returns the current maximum TPS.
//
// MaxTPS is concurrent-safe.
func MaxTPS() int {
	return int(atomic.LoadInt32(&currentMaxTPS))
}

// CurrentTPS returns the current TPS (ticks per second),
// that represents how many update function is called in a second.
//
// CurrentTPS is concurrent-safe.
func CurrentTPS() float64 {
	return clock.CurrentTPS()
}

// UncappedTPS is a special TPS value that means the game doesn't have limitation on TPS.
const UncappedTPS = clock.UncappedTPS

// SetMaxTPS sets the maximum TPS (ticks per second),
// that represents how many updating function is called per second.
// The initial value is 60.
//
// If tps is UncappedTPS, TPS is uncapped and the game is updated per frame.
// If tps is negative but not UncappedTPS, SetMaxTPS panics.
//
// SetMaxTPS is concurrent-safe.
func SetMaxTPS(tps int) {
	if tps < 0 && tps != UncappedTPS {
		panic("ebiten: tps must be >= 0 or UncappedTPS")
	}
	atomic.StoreInt32(&currentMaxTPS, int32(tps))
}

// IsScreenTransparent reports whether the window is transparent.
//
// IsScreenTransparent is concurrent-safe.
func IsScreenTransparent() bool {
	return uiDriver().IsScreenTransparent()
}

// SetScreenTransparent sets the state if the window is transparent.
//
// SetScreenTransparent panics if SetScreenTransparent is called after the main loop.
//
// SetScreenTransparent does nothing on mobiles.
//
// SetScreenTransparent is concurrent-safe.
func SetScreenTransparent(transparent bool) {
	uiDriver().SetScreenTransparent(transparent)
}

// SetInitFocused sets whether the application is focused on show.
// The default value is true, i.e., the application is focused.
// Note that the application does not proceed if this is not focused by default.
// This behavior can be changed by SetRunnableInBackground.
//
// SetInitFocused does nothing on mobile.
//
// SetInitFocused panics if this is called after the main loop.
//
// SetInitFocused is cuncurrent-safe.
func SetInitFocused(focused bool) {
	uiDriver().SetInitFocused(focused)
}
<commit_msg>ebiten: Add comments about SetCursorShape / CursorShape<commit_after>// Copyright 2014 Hajime Hoshi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package ebiten

import (
	"sync/atomic"

	"github.com/hajimehoshi/ebiten/v2/internal/clock"
	"github.com/hajimehoshi/ebiten/v2/internal/driver"
)

// Game defines necessary functions for a game.
type Game interface {
	// Update updates a game by one tick. The given argument represents a screen image.
	//
	// Update updates only the game logic and Draw draws the screen.
	//
	// In the first frame, it is ensured that Update is called at least once before Draw. You can use Update
	// to initialize the game state.
	//
	// After the first frame, Update might not be called or might be called once
	// or more for one frame. The frequency is determined by the current TPS (tick-per-second).
	Update() error

	// Draw draws the game screen by one frame.
	//
	// The give argument represents a screen image. The updated content is adopted as the game screen.
	Draw(screen *Image)

	// Layout accepts a native outside size in device-independent pixels and returns the game's logical screen
	// size.
	//
	// On desktops, the outside is a window or a monitor (fullscreen mode). On browsers, the outside is a body
	// element. On mobiles, the outside is the view's size.
	//
	// Even though the outside size and the screen size differ, the rendering scale is automatically adjusted to
	// fit with the outside.
	//
	// Layout is called almost every frame.
	//
	// It is ensured that Layout is invoked before Update is called in the first frame.
	//
	// If Layout returns non-positive numbers, the caller can panic.
	//
	// You can return a fixed screen size if you don't care, or you can also return a calculated screen size
	// adjusted with the given outside size.
	Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int)
}

// DefaultTPS represents a default ticks per second, that represents how many times game updating happens in a second.
const DefaultTPS = 60

// CurrentFPS returns the current number of FPS (frames per second), that represents
// how many swapping buffer happens per second.
//
// On some environments, CurrentFPS doesn't return a reliable value since vsync doesn't work well there.
// If you want to measure the application's speed, Use CurrentTPS.
//
// CurrentFPS is concurrent-safe.
func CurrentFPS() float64 {
	return clock.CurrentFPS()
}

var (
	isScreenClearedEveryFrame = int32(1)
	isRunGameEnded_           = int32(0)
	currentMaxTPS             = int32(DefaultTPS)
)

// SetScreenClearedEveryFrame enables or disables the clearing of the screen at the beginning of each frame.
// The default value is true and the screen is cleared each frame by default.
//
// SetScreenClearedEveryFrame is concurrent-safe.
func SetScreenClearedEveryFrame(cleared bool) {
	v := int32(0)
	if cleared {
		v = 1
	}
	atomic.StoreInt32(&isScreenClearedEveryFrame, v)
	theUIContext.setScreenClearedEveryFrame(cleared)
}

// IsScreenClearedEveryFrame returns true if the frame isn't cleared at the beginning.
//
// IsScreenClearedEveryFrame is concurrent-safe.
func IsScreenClearedEveryFrame() bool {
	return atomic.LoadInt32(&isScreenClearedEveryFrame) != 0
}

type imageDumperGame struct {
	game Game
	d    *imageDumper
	err  error
}

func (i *imageDumperGame) Update() error {
	if i.err != nil {
		return i.err
	}
	if i.d == nil {
		i.d = &imageDumper{g: i.game}
	}
	return i.d.update()
}

func (i *imageDumperGame) Draw(screen *Image) {
	if i.err != nil {
		return
	}

	i.game.Draw(screen)
	i.err = i.d.dump(screen)
}

func (i *imageDumperGame) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) {
	return i.game.Layout(outsideWidth, outsideHeight)
}

// RunGame starts the main loop and runs the game.
// game's Update function is called every tick to update the game logic.
// game's Draw function is, if it exists, called every frame to draw the screen.
// game's Layout function is called when necessary, and you can specify the logical screen size by the function.
//
// game must implement Game interface.
// Game's Draw function is optional, but it is recommended to implement Draw to seperate updating the logic and
// rendering.
//
// RunGame is a more flexibile form of Run due to game's Layout function.
// You can make a resizable window if you use RunGame, while you cannot if you use Run.
// RunGame is more sophisticated way than Run and hides the notion of 'scale'.
//
// While Run specifies the window size, RunGame does not.
// You need to call SetWindowSize before RunGame if you want.
// Otherwise, a default window size is adopted.
//
// Some functions (ScreenScale, SetScreenScale, SetScreenSize) are not available with RunGame.
//
// On browsers, it is strongly recommended to use iframe if you embed an Ebiten application in your website.
//
// RunGame must be called on the main thread.
// Note that Ebiten bounds the main goroutine to the main OS thread by runtime.LockOSThread.
//
// Ebiten tries to call game's Update function 60 times a second by default. In other words,
// TPS (ticks per second) is 60 by default.
// This is not related to framerate (display's refresh rate).
//
// RunGame returns error when 1) error happens in the underlying graphics driver, 2) audio error happens or
// 3) f returns error. In the case of 3), RunGame returns the same error.
//
// The size unit is device-independent pixel.
//
// Don't call RunGame twice or more in one process.
func RunGame(game Game) error {
	defer atomic.StoreInt32(&isRunGameEnded_, 1)

	initializeWindowPositionIfNeeded(WindowSize())
	theUIContext.set(&imageDumperGame{
		game: game,
	})
	if err := uiDriver().Run(theUIContext); err != nil {
		if err == driver.RegularTermination {
			return nil
		}
		return err
	}
	return nil
}

func isRunGameEnded() bool {
	return atomic.LoadInt32(&isRunGameEnded_) != 0
}

// ScreenSizeInFullscreen returns the size in device-independent pixels when the game is fullscreen.
// The adopted monitor is the 'current' monitor which the window belongs to.
// The returned value can be given to Run or SetSize function if the perfectly fit fullscreen is needed.
//
// On browsers, ScreenSizeInFullscreen returns the 'window' (global object) size, not 'screen' size since an Ebiten
// game should not know the outside of the window object.
//
// On mobiles, ScreenSizeInFullscreen returns (0, 0) so far.
//
// ScreenSizeInFullscreen's use cases are limited. If you are making a fullscreen application, you can use RunGame and
// the Game interface's Layout function instead. If you are making a not-fullscreen application but the application's
// behavior depends on the monitor size, ScreenSizeInFullscreen is useful.
//
// ScreenSizeInFullscreen must be called on the main thread before ebiten.Run, and is concurrent-safe after
// ebiten.Run.
func ScreenSizeInFullscreen() (int, int) {
	return uiDriver().ScreenSizeInFullscreen()
}

// CursorMode returns the current cursor mode.
//
// CursorMode returns CursorModeHidden on mobiles.
//
// CursorMode is concurrent-safe.
func CursorMode() CursorModeType {
	return CursorModeType(uiDriver().CursorMode())
}

// SetCursorMode sets the render and capture mode of the mouse cursor.
// CursorModeVisible sets the cursor to always be visible.
// CursorModeHidden hides the system cursor when over the window.
// CursorModeCaptured hides the system cursor and locks it to the window.
//
// CursorModeCaptured also works on browsers.
// When the user exits the captured mode not by SetCursorMode but by the UI (e.g., pressing ESC),
// the previous cursor mode is set automatically.
//
// SetCursorMode does nothing on mobiles.
//
// SetCursorMode is concurrent-safe.
func SetCursorMode(mode CursorModeType) {
	uiDriver().SetCursorMode(driver.CursorMode(mode))
}

// CursorShape returns the current cursor shape.
//
// CursorShape returns CursorShapeDefault on mobiles.
//
// CursorShape is concurrent-safe.
func CursorShape() CursorShapeType {
	return CursorShapeType(uiDriver().CursorShape())
}

// SetCursorShape sets the cursor shape.
//
// SetCursorShape is concurrent-safe.
func SetCursorShape(shape CursorShapeType) {
	uiDriver().SetCursorShape(driver.CursorShape(shape))
}

// IsFullscreen reports whether the current mode is fullscreen or not.
//
// IsFullscreen always returns false on mobiles.
//
// IsFullscreen is concurrent-safe.
func IsFullscreen() bool {
	return uiDriver().IsFullscreen()
}

// SetFullscreen changes the current mode to fullscreen or not on desktops and browsers.
//
// In fullscreen mode, the game screen is automatically enlarged
// to fit with the monitor. The current scale value is ignored.
//
// On desktops, Ebiten uses 'windowed' fullscreen mode, which doesn't change
// your monitor's resolution.
//
// On browsers, triggering fullscreen requires a user gesture otherwise SetFullscreen does nothing but leave an error message in console.
// This behaviour varies across browser implementations, your mileage may vary.
//
// SetFullscreen does nothing on mobiles.
//
// SetFullscreen does nothing on macOS when the window is fullscreened natively by the macOS desktop
// instead of SetFullscreen(true).
//
// SetFullscreen is concurrent-safe.
func SetFullscreen(fullscreen bool) {
	uiDriver().SetFullscreen(fullscreen)
}

// IsFocused returns a boolean value indicating whether
// the game is in focus or in the foreground.
//
// IsFocused will only return true if IsRunnableOnUnfocused is false.
//
// IsFocused is concurrent-safe.
func IsFocused() bool {
	return uiDriver().IsFocused()
}

// IsRunnableOnUnfocused returns a boolean value indicating whether
// the game runs even in background.
//
// IsRunnableOnUnfocused is concurrent-safe.
func IsRunnableOnUnfocused() bool {
	return uiDriver().IsRunnableOnUnfocused()
}

// SetRunnableOnUnfocused sets the state if the game runs even in background.
//
// If the given value is true, the game runs even in background e.g. when losing focus.
// The initial state is true.
//
// Known issue: On browsers, even if the state is on, the game doesn't run in background tabs.
// This is because browsers throttles background tabs not to often update.
//
// SetRunnableOnUnfocused does nothing on mobiles so far.
//
// SetRunnableOnUnfocused is concurrent-safe.
func SetRunnableOnUnfocused(runnableOnUnfocused bool) {
	uiDriver().SetRunnableOnUnfocused(runnableOnUnfocused)
}

// DeviceScaleFactor returns a device scale factor value of the current monitor which the window belongs to.
//
// DeviceScaleFactor returns a meaningful value on high-DPI display environment,
// otherwise DeviceScaleFactor returns 1.
//
// DeviceScaleFactor might panic on init function on some devices like Android.
// Then, it is not recommended to call DeviceScaleFactor from init functions.
//
// DeviceScaleFactor must be called on the main thread before the main loop, and is concurrent-safe after the main
// loop.
//
// DeviceScaleFactor is concurrent-safe.
//
// BUG: DeviceScaleFactor value is not affected by SetWindowPosition before RunGame (#1575).
func DeviceScaleFactor() float64 {
	return uiDriver().DeviceScaleFactor()
}

// IsVsyncEnabled returns a boolean value indicating whether
// the game uses the display's vsync.
//
// IsVsyncEnabled is concurrent-safe.
func IsVsyncEnabled() bool {
	return uiDriver().IsVsyncEnabled()
}

// SetVsyncEnabled sets a boolean value indicating whether
// the game uses the display's vsync.
//
// If the given value is true, the game tries to sync the display's refresh rate.
// If false, the game ignores the display's refresh rate.
// The initial value is true.
// By disabling vsync, the game works more efficiently but consumes more CPU.
//
// Note that the state doesn't affect TPS (ticks per second, i.e. how many the run function is
// updated per second).
//
// SetVsyncEnabled does nothing on mobiles so far.
//
// SetVsyncEnabled is concurrent-safe.
func SetVsyncEnabled(enabled bool) {
	uiDriver().SetVsyncEnabled(enabled)
}

// MaxTPS returns the current maximum TPS.
//
// MaxTPS is concurrent-safe.
func MaxTPS() int {
	return int(atomic.LoadInt32(&currentMaxTPS))
}

// CurrentTPS returns the current TPS (ticks per second),
// that represents how many update function is called in a second.
//
// CurrentTPS is concurrent-safe.
func CurrentTPS() float64 {
	return clock.CurrentTPS()
}

// UncappedTPS is a special TPS value that means the game doesn't have limitation on TPS.
const UncappedTPS = clock.UncappedTPS

// SetMaxTPS sets the maximum TPS (ticks per second),
// that represents how many updating function is called per second.
// The initial value is 60.
//
// If tps is UncappedTPS, TPS is uncapped and the game is updated per frame.
// If tps is negative but not UncappedTPS, SetMaxTPS panics.
//
// SetMaxTPS is concurrent-safe.
func SetMaxTPS(tps int) {
	if tps < 0 && tps != UncappedTPS {
		panic("ebiten: tps must be >= 0 or UncappedTPS")
	}
	atomic.StoreInt32(&currentMaxTPS, int32(tps))
}

// IsScreenTransparent reports whether the window is transparent.
//
// IsScreenTransparent is concurrent-safe.
func IsScreenTransparent() bool {
	return uiDriver().IsScreenTransparent()
}

// SetScreenTransparent sets the state if the window is transparent.
//
// SetScreenTransparent panics if SetScreenTransparent is called after the main loop.
//
// SetScreenTransparent does nothing on mobiles.
//
// SetScreenTransparent is concurrent-safe.
func SetScreenTransparent(transparent bool) {
	uiDriver().SetScreenTransparent(transparent)
}

// SetInitFocused sets whether the application is focused on show.
// The default value is true, i.e., the application is focused.
// Note that the application does not proceed if this is not focused by default.
// This behavior can be changed by SetRunnableInBackground.
//
// SetInitFocused does nothing on mobile.
//
// SetInitFocused panics if this is called after the main loop.
//
// SetInitFocused is cuncurrent-safe.
func SetInitFocused(focused bool) {
	uiDriver().SetInitFocused(focused)
}
<|endoftext|>


<commit_before>package raft

import (
	"math/rand"
	"time"
)

type TimeSettings struct {
	TickerDuration time.Duration

	// Election timeout low value - 2x this value is used as high value.
	ElectionTimeoutLow time.Duration
}

// Check values of a TimeSettings value:
//
//    tickerDuration  must be greater than zero.
//    electionTimeout must be greater than tickerDuration.
//
// These are just basic sanity checks and currently don't include the
// softer usefulness checks recommended by the raft protocol.
func ValidateTimeSettings(timeSettings TimeSettings) string {
	if timeSettings.TickerDuration.Nanoseconds() <= 0 {
		return "TickerDuration must be greater than zero"
	}
	if timeSettings.ElectionTimeoutLow.Nanoseconds() <= timeSettings.TickerDuration.Nanoseconds() {
		return "ElectionTimeoutLow must be greater than TickerDuration"
	}

	return ""
}

type electionTimeoutTracker struct {
	electionTimeoutLow     time.Duration
	currentElectionTimeout time.Duration
	electionTimeoutTime    time.Time
}

func newElectionTimeoutTracker(electionTimeoutLow time.Duration, now time.Time) *electionTimeoutTracker {
	ett := &electionTimeoutTracker{
		electionTimeoutLow,
		0,   // temp value, to be replaced later in initialization
		now, // temp value, to be replaced before goroutine start
	}

	ett.chooseNewRandomElectionTimeoutAndTouch(now)

	return ett
}

func (ett *electionTimeoutTracker) chooseNewRandomElectionTimeoutAndTouch(now time.Time) {
	// #5.2-p6s2: ..., election timeouts are chosen randomly from a fixed
	// interval (e.g., 150-300ms)
	ett.currentElectionTimeout = ett.electionTimeoutLow + time.Duration(rand.Int63n(int64(ett.electionTimeoutLow)+1))
	ett.touch(now)
}

func (ett *electionTimeoutTracker) touch(now time.Time) {
	ett.electionTimeoutTime = now.Add(ett.currentElectionTimeout)
}

func (ett *electionTimeoutTracker) electionTimeoutHasOccurred(now time.Time) bool {
	return now.After(ett.electionTimeoutTime)
}
<commit_msg>electionTimeoutTracker uses it's own Rand seeded with current time<commit_after>package raft

import (
	"math/rand"
	"time"
)

type TimeSettings struct {
	TickerDuration time.Duration

	// Election timeout low value - 2x this value is used as high value.
	ElectionTimeoutLow time.Duration
}

// Check values of a TimeSettings value:
//
//    tickerDuration  must be greater than zero.
//    electionTimeout must be greater than tickerDuration.
//
// These are just basic sanity checks and currently don't include the
// softer usefulness checks recommended by the raft protocol.
func ValidateTimeSettings(timeSettings TimeSettings) string {
	if timeSettings.TickerDuration.Nanoseconds() <= 0 {
		return "TickerDuration must be greater than zero"
	}
	if timeSettings.ElectionTimeoutLow.Nanoseconds() <= timeSettings.TickerDuration.Nanoseconds() {
		return "ElectionTimeoutLow must be greater than TickerDuration"
	}

	return ""
}

type electionTimeoutTracker struct {
	r                      *rand.Rand
	electionTimeoutLow     time.Duration
	currentElectionTimeout time.Duration
	electionTimeoutTime    time.Time
}

func newElectionTimeoutTracker(electionTimeoutLow time.Duration, now time.Time) *electionTimeoutTracker {
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	ett := &electionTimeoutTracker{
		r,
		electionTimeoutLow,
		0,   // temp value, to be replaced later in initialization
		now, // temp value, to be replaced before goroutine start
	}

	ett.chooseNewRandomElectionTimeoutAndTouch(now)

	return ett
}

func (ett *electionTimeoutTracker) chooseNewRandomElectionTimeoutAndTouch(now time.Time) {
	// #5.2-p6s2: ..., election timeouts are chosen randomly from a fixed
	// interval (e.g., 150-300ms)
	ett.currentElectionTimeout = ett.electionTimeoutLow + time.Duration(ett.r.Int63n(int64(ett.electionTimeoutLow)+1))
	ett.touch(now)
}

func (ett *electionTimeoutTracker) touch(now time.Time) {
	ett.electionTimeoutTime = now.Add(ett.currentElectionTimeout)
}

func (ett *electionTimeoutTracker) electionTimeoutHasOccurred(now time.Time) bool {
	return now.After(ett.electionTimeoutTime)
}
<|endoftext|>


<commit_before>/*
 Compiles HTML templates to be used for rendering pages during dynamic content
 insertion
*/

package main

import (
	"bytes"
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"github.com/dchest/htmlmin"
	"html/template"
	"io"
	"io/ioutil"
	"os"
	"strings"
)

// templateStore stores the static part of HTML templates and the corresponding
// truncated MD5 hash of said template
type templateStore struct {
	Parts []string
	Hash  string
}

// templateMap stores all available templates
type templateMap map[string]templateStore

// resources exports temolates and their hashes by language
var resources templateMap

// compileTemplates reads template HTML from disk, injects dynamic variables,
// hashes and stores them
func compileTemplates() {
	// Only one for now, but there will be more later
	raw := map[string]string{}
	for _, name := range []string{"index"} {
		file, err := ioutil.ReadFile("./tmpl/" + name + ".html")
		throw(err)
		raw[name] = string(file)
	}
	newResources := templateMap{}
	index, mobile := indexTemplate(raw["index"])
	newResources["index"] = index
	newResources["mobile"] = mobile
	resources = newResources
}

// clientFileHash is the combined, shortened MD5 hash of all client files
var clientFileHash string

type templateVars struct {
	Config                                       template.JS
	Navigation, ClientHash, ConfigHash, MediaURL string
	IsMobile                                     bool
}

// indexTemplate compiles the HTML template for thread and board pages of the
// imageboard
func indexTemplate(raw string) (templateStore, templateStore) {
	vars := templateVars{
		ConfigHash: configHash,
		MediaURL:   config.Hard.HTTP.Media,
	}
	js, err := json.Marshal(clientConfig)
	throw(err)
	vars.Config = template.JS(js)
	vars.Navigation = boardNavigation()
	hash := hashClientFiles()
	vars.ClientHash = hash
	clientFileHash = hash

	tmpl, err1 := template.New("index").Parse(raw)
	throw(err1)

	// Rigt now the desktop and mobile templates are almost identical. This will
	// change, when we get a dedicated mobile GUI.
	return buildIndexTemplate(tmpl, vars, false),
		buildIndexTemplate(tmpl, vars, true)
}

// hashClientFiles reads all client files and produces a truncated MD5 hash.
// Used for versioning in query strings for transparent client version
// transition.
func hashClientFiles() string {
	// Gather all files
	files := []string{}
	args := [][2]string{
		{"./www/css", ".css"},
		{"./www/js", ".js"},
		{"./www/js/vendor", ".js"},
		{"./www/js/es5", ".js"},
		{"./www/js/es6", ".js"},
		{"./www/js/lang", ".js"},
	}
	for _, pair := range args {
		files = append(files, scanDir(pair[0], pair[1])...)
	}

	// Read all files into the hashing function
	hasher := md5.New()
	for _, file := range files {
		copyFile(file, hasher)
	}
	return hex.EncodeToString(hasher.Sum(nil))[:16]
}

// scanDir returns files from a folder, that end with the provided extension
func scanDir(path string, suffix string) (filtered []string) {
	for _, file := range ls(path) {
		if strings.HasSuffix(file, suffix) {
			filtered = append(filtered, path+"/"+file)
		}
	}
	return
}

// ls returns the contents of a directory
func ls(path string) []string {
	dir, err := os.Open(path)
	throw(err)
	defer dir.Close()
	files, err1 := dir.Readdirnames(0)
	throw(err1)
	return files
}

// copyFile reads a file from disk and copies it into the writer
func copyFile(path string, writer io.Writer) {
	file, err := os.Open(path)
	throw(err)
	defer file.Close()
	_, err1 := io.Copy(writer, file)
	throw(err1)
}

// boardNavigation renders interboard navigation we put in the top banner
func boardNavigation() (html string) {
	html = `<b id="navTop">[`

	// Actual boards
	boards := config.Boards.Enabled
	for i, board := range boards {
		if board == config.Boards.Staff {
			continue
		}
		if i > 0 {
			html += ` / `
		}
		html += fmt.Sprintf(`<a href="../%v/" class="history">%v</a>`, board,
			board)
	}

	// Add custom URLs to board navigation
	for _, link := range config.Boards.Psuedo {
		html += fmt.Sprintf(` / <a href="%v">%v</a>`, link[1], link[0])
	}
	html += `]</b>`
	return
}

// buildIndexTemplate constructs the HTML template array, minifies and hashes it
func buildIndexTemplate(tmpl *template.Template, vars templateVars, isMobile bool) templateStore {
	vars.IsMobile = isMobile
	buffer := bytes.Buffer{}
	throw(tmpl.Execute(&buffer, vars))
	minified, err := htmlmin.Minify(buffer.Bytes(), &htmlmin.Options{
		MinifyScripts: true,
	})
	throw(err)
	hasher := md5.New()
	hasher.Write(minified)
	return templateStore{
		strings.Split(string(minified), "$$$"),
		hex.EncodeToString(hasher.Sum(nil))[:16],
	}
}
<commit_msg>Store templates as []byte<commit_after>/*
 Compiles HTML templates to be used for rendering pages during dynamic content
 insertion
*/

package main

import (
	"bytes"
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"github.com/dchest/htmlmin"
	"html/template"
	"io"
	"io/ioutil"
	"os"
	"strings"
)

// templateStore stores the static part of HTML templates and the corresponding
// truncated MD5 hash of said template
type templateStore struct {
	Parts [][]byte
	Hash  string
}

// templateMap stores all available templates
type templateMap map[string]templateStore

// resources exports temolates and their hashes by language
var resources templateMap

// compileTemplates reads template HTML from disk, injects dynamic variables,
// hashes and stores them
func compileTemplates() {
	// Only one for now, but there will be more later
	raw := map[string]string{}
	for _, name := range []string{"index"} {
		file, err := ioutil.ReadFile("./tmpl/" + name + ".html")
		throw(err)
		raw[name] = string(file)
	}
	newResources := templateMap{}
	index, mobile := indexTemplate(raw["index"])
	newResources["index"] = index
	newResources["mobile"] = mobile
	resources = newResources
}

// clientFileHash is the combined, shortened MD5 hash of all client files
var clientFileHash string

type templateVars struct {
	Config                                       template.JS
	Navigation, ClientHash, ConfigHash, MediaURL string
	IsMobile                                     bool
}

// indexTemplate compiles the HTML template for thread and board pages of the
// imageboard
func indexTemplate(raw string) (templateStore, templateStore) {
	vars := templateVars{
		ConfigHash: configHash,
		MediaURL:   config.Hard.HTTP.Media,
	}
	js, err := json.Marshal(clientConfig)
	throw(err)
	vars.Config = template.JS(js)
	vars.Navigation = boardNavigation()
	hash := hashClientFiles()
	vars.ClientHash = hash
	clientFileHash = hash

	tmpl, err1 := template.New("index").Parse(raw)
	throw(err1)

	// Rigt now the desktop and mobile templates are almost identical. This will
	// change, when we get a dedicated mobile GUI.
	return buildIndexTemplate(tmpl, vars, false),
		buildIndexTemplate(tmpl, vars, true)
}

// hashClientFiles reads all client files and produces a truncated MD5 hash.
// Used for versioning in query strings for transparent client version
// transition.
func hashClientFiles() string {
	// Gather all files
	files := []string{}
	args := [][2]string{
		{"./www/css", ".css"},
		{"./www/js", ".js"},
		{"./www/js/vendor", ".js"},
		{"./www/js/es5", ".js"},
		{"./www/js/es6", ".js"},
		{"./www/js/lang", ".js"},
	}
	for _, pair := range args {
		files = append(files, scanDir(pair[0], pair[1])...)
	}

	// Read all files into the hashing function
	hasher := md5.New()
	for _, file := range files {
		copyFile(file, hasher)
	}
	return hex.EncodeToString(hasher.Sum(nil))[:16]
}

// scanDir returns files from a folder, that end with the provided extension
func scanDir(path string, suffix string) (filtered []string) {
	for _, file := range ls(path) {
		if strings.HasSuffix(file, suffix) {
			filtered = append(filtered, path+"/"+file)
		}
	}
	return
}

// ls returns the contents of a directory
func ls(path string) []string {
	dir, err := os.Open(path)
	throw(err)
	defer dir.Close()
	files, err1 := dir.Readdirnames(0)
	throw(err1)
	return files
}

// copyFile reads a file from disk and copies it into the writer
func copyFile(path string, writer io.Writer) {
	file, err := os.Open(path)
	throw(err)
	defer file.Close()
	_, err1 := io.Copy(writer, file)
	throw(err1)
}

// boardNavigation renders interboard navigation we put in the top banner
func boardNavigation() (html string) {
	html = `<b id="navTop">[`

	// Actual boards
	boards := config.Boards.Enabled
	for i, board := range boards {
		if board == config.Boards.Staff {
			continue
		}
		if i > 0 {
			html += ` / `
		}
		html += fmt.Sprintf(`<a href="../%v/" class="history">%v</a>`, board,
			board)
	}

	// Add custom URLs to board navigation
	for _, link := range config.Boards.Psuedo {
		html += fmt.Sprintf(` / <a href="%v">%v</a>`, link[1], link[0])
	}
	html += `]</b>`
	return
}

// buildIndexTemplate constructs the HTML template array, minifies and hashes it
func buildIndexTemplate(tmpl *template.Template, vars templateVars, isMobile bool) templateStore {
	vars.IsMobile = isMobile
	buffer := bytes.Buffer{}
	throw(tmpl.Execute(&buffer, vars))
	minified, err := htmlmin.Minify(buffer.Bytes(), &htmlmin.Options{
		MinifyScripts: true,
	})
	throw(err)
	hasher := md5.New()
	hasher.Write(minified)
	return templateStore{
		bytes.Split(minified, []byte("$$$")),
		hex.EncodeToString(hasher.Sum(nil))[:16],
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/ymotongpoo/goltsv"
)

type Todo struct {
	Number int
	Title  string
	Done   bool
}

func ReadTodos() ([]Todo, error) {
	path := getTodosPath()
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}

	buf := bytes.NewBuffer(data)
	reader := goltsv.NewReader(buf)
	records, err := reader.ReadAll()
	if err != nil {
		return nil, err
	}

	todos := []Todo{}
	for i, record := range records {
		var title string
		var done bool

		for k, v := range record {
			switch k {
			case "title":
				title = v
			case "done":
				done = (v == "true")
			}
		}

		todo := Todo{Number: i + 1, Title: title, Done: done}
		todos = append(todos, todo)
	}

	return todos, nil
}

func getTodosPath() string {
	path := os.Getenv("TODO_PATH")
	if path == "" {
		path = os.Getenv("HOME")
	}

	return filepath.Join(path, ".todo")
}
<commit_msg>Create a todo file if it doesn't exist<commit_after>package main

import (
	"bytes"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/ymotongpoo/goltsv"
)

type Todo struct {
	Number int
	Title  string
	Done   bool
}

func ReadTodos() ([]Todo, error) {
	path := getTodosPath()
	if !fileIsExist(path) {
		err := createNewFile(path)
		if err != nil {
			return nil, err
		}
	}

	data, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}

	buf := bytes.NewBuffer(data)
	reader := goltsv.NewReader(buf)
	records, err := reader.ReadAll()
	if err != nil {
		return nil, err
	}

	todos := []Todo{}
	for i, record := range records {
		var title string
		var done bool

		for k, v := range record {
			switch k {
			case "title":
				title = v
			case "done":
				done = (v == "true")
			}
		}

		todo := Todo{Number: i + 1, Title: title, Done: done}
		todos = append(todos, todo)
	}

	return todos, nil
}

func getTodosPath() string {
	path := os.Getenv("TODO_PATH")
	if path == "" {
		path = os.Getenv("HOME")
	}

	return filepath.Join(path, ".todo")
}

func fileIsExist(path string) bool {
	_, err := os.Stat(path)
	return err == nil
}

func createNewFile(path string) error {
	_, err := os.Create(path)
	return err
}
<|endoftext|>


<commit_before>package main

import (
	//"os"
	"fmt"
	"github.com/urfave/cli"
)

var toolCommands = []cli.Command {
	{
		Name: "beep_off",
		Usage: "Beep off for ACS Reader",
		Action: beepOff,
		Flags: commonFlags,
	},
	{
		Name: "pin_status",
		Usage: "PINステータス",
		Action: pinStatus,
		Before: checkCard,
		Flags: commonFlags,
	},
	{
		Name: "find_ap",
		Usage: "search AP",
		Action: findAP,
		Flags: commonFlags,
	},
}

func beepOff(c *cli.Context) error {
	reader := NewReader(c)
	defer reader.Finalize()
	reader.WaitForCard()
	reader.Tx("FF 00 52 00 00")
	return nil
}

func pinStatus(c *cli.Context) error {
	reader := NewReader(c)
	defer reader.Finalize()
	reader.WaitForCard()

	aid := "D3 92 f0 00 26 01 00 00 00 01"
	apdu := "00 A4 04 0C" + " 0A " + aid
	sw1, sw2, _:= reader.Tx(apdu)

	reader.Tx("00 a4 02 0C 02 00 18") // IEF for AUTH
	sw1, sw2, _ = reader.Tx("00 20 00 80")
	if (sw1 == 0x63) {
		fmt.Printf("認証用PIN: のこり%d回\n", sw2 - 0xC0)
	}
	reader.Tx("00 a4 02 0C 02 00 1B") // IEF for SIGN
	sw1, sw2, _ = reader.Tx("00 20 00 80")
	if (sw1 == 0x63) {
		fmt.Printf("署名用PIN: のこり%d回\n", sw2 - 0xC0)
	}

	aid = "D3 92 10 00 31 00 01 01 04 08"
	apdu = "00 A4 04 0C" + " 0A " + aid
	reader.Tx(apdu)
	reader.Tx("00 a4 02 0C 02 00 11") // IEF for MYNUM
	reader.Tx("00 20 00 80")
	sw1, sw2, _ = reader.Tx("00 20 00 80")
	if (sw1 == 0x63) {
		fmt.Printf("券面入力補助PIN: のこり%d回\n", sw2 - 0xC0)
	}

	return nil
}

func findAP(c *cli.Context) error {
	var prefix = []byte{}

	reader := NewReader(c)
	defer reader.Finalize()
	reader.WaitForCard()
	ret := findDF(reader, prefix)
	for _, ap := range ret {
		fmt.Printf("found ap: % X\n", ap)
	}
	return nil
}

func findDF(reader *Reader, prefix []byte) [][]byte {
	var tmp [][]byte
	i := len(prefix)
	l := i + 1
	buf := append(prefix, 0)
	for n := 0; n<255; n++ {
		buf[i] = byte(n)
		apdu := "00 A4 04 0C " +
			fmt.Sprintf("%02X ", l) +
			fmt.Sprintf("% X", buf)
		sw1, sw2, _ := reader.Tx(apdu)
		if(sw1 == 0x90 && sw2 == 0x00){
			ret := findDF(reader, buf)
			if len(ret) == 0 {
				//fmt.Printf("found ap % X\n", buf)
				dup := make([]byte, len(buf))
				copy(dup, buf)
				tmp = append(tmp, dup)
			}else{
				tmp = append(tmp, ret...)
			}
		}
	}
	return tmp
}
<commit_msg>謎のPINステータス<commit_after>package main

import (
	//"os"
	"fmt"
	"github.com/urfave/cli"
)

var toolCommands = []cli.Command {
	{
		Name: "beep_off",
		Usage: "Beep off for ACS Reader",
		Action: beepOff,
		Flags: commonFlags,
	},
	{
		Name: "pin_status",
		Usage: "PINステータス",
		Action: pinStatus,
		Before: checkCard,
		Flags: commonFlags,
	},
	{
		Name: "find_ap",
		Usage: "search AP",
		Action: findAP,
		Flags: commonFlags,
	},
}

func beepOff(c *cli.Context) error {
	reader := NewReader(c)
	defer reader.Finalize()
	reader.WaitForCard()
	reader.Tx("FF 00 52 00 00")
	return nil
}

func pinStatus(c *cli.Context) error {
	reader := NewReader(c)
	defer reader.Finalize()
	reader.WaitForCard()

	aid := "D3 92 f0 00 26 01 00 00 00 01" // 公的個人認証
	apdu := "00 A4 04 0C" + " 0A " + aid
	sw1, sw2, _:= reader.Tx(apdu)

	reader.Tx("00 a4 02 0C 02 00 18") // IEF for AUTH
	sw1, sw2, _ = reader.Tx("00 20 00 80")
	if (sw1 == 0x63) {
		fmt.Printf("認証用PIN: のこり%d回\n", sw2 - 0xC0)
	}
	reader.Tx("00 a4 02 0C 02 00 1B") // IEF for SIGN
	sw1, sw2, _ = reader.Tx("00 20 00 80")
	if (sw1 == 0x63) {
		fmt.Printf("署名用PIN: のこり%d回\n", sw2 - 0xC0)
	}

	aid = "D3 92 10 00 31 00 01 01 04 08" // 券面事項DF
	apdu = "00 A4 04 0C" + " 0A " + aid
	reader.Tx(apdu)
	reader.Tx("00 a4 02 0C 02 00 11") // IEF
	reader.Tx("00 20 00 80")
	sw1, sw2, _ = reader.Tx("00 20 00 80")
	if (sw1 == 0x63) {
		fmt.Printf("券面入力補助PIN: のこり%d回\n", sw2 - 0xC0)
	}

	aid = "D3 92 10 00 31 00 01 01 01 00" // 謎
	apdu = "00 A4 04 0C" + " 0A " + aid
	reader.Tx(apdu)
	reader.Tx("00 a4 02 0C 02 00 1C") // IEF
	reader.Tx("00 20 00 80")
	sw1, sw2, _ = reader.Tx("00 20 00 80")
	if (sw1 == 0x63) {
		fmt.Printf("謎のPIN1: のこり%d回\n", sw2 - 0xC0)
	}

	aid = "D3 92 10 00 31 00 01 01 04 01" // 住基?
	apdu = "00 A4 04 0C" + " 0A " + aid
	reader.Tx(apdu)
	reader.Tx("00 a4 02 0C 02 00 1C") // IEF
	reader.Tx("00 20 00 80")
	sw1, sw2, _ = reader.Tx("00 20 00 80")
	if (sw1 == 0x63) {
		fmt.Printf("謎のPIN2: のこり%d回\n", sw2 - 0xC0)
	}

	return nil
}

func findAP(c *cli.Context) error {
	var prefix = []byte{}

	reader := NewReader(c)
	defer reader.Finalize()
	reader.WaitForCard()
	ret := findDF(reader, prefix)
	for _, ap := range ret {
		fmt.Printf("found ap: % X\n", ap)
	}
	return nil
}

func findDF(reader *Reader, prefix []byte) [][]byte {
	var tmp [][]byte
	i := len(prefix)
	l := i + 1
	buf := append(prefix, 0)
	for n := 0; n<255; n++ {
		buf[i] = byte(n)
		apdu := "00 A4 04 0C " +
			fmt.Sprintf("%02X ", l) +
			fmt.Sprintf("% X", buf)
		sw1, sw2, _ := reader.Tx(apdu)
		if(sw1 == 0x90 && sw2 == 0x00){
			ret := findDF(reader, buf)
			if len(ret) == 0 {
				//fmt.Printf("found ap % X\n", buf)
				dup := make([]byte, len(buf))
				copy(dup, buf)
				tmp = append(tmp, dup)
			}else{
				tmp = append(tmp, ret...)
			}
		}
	}
	return tmp
}
<|endoftext|>


<commit_before>package CloudForest

import ()

//Tree represents a single decision tree.
type Tree struct {
	//Tree int
	Root   *Node
	Target string
	Weight float64
}

func NewTree() *Tree {
	return &Tree{new(Node), "", -1.0}
}

//AddNode adds a node a the specified path with the specified pred value and/or
//Splitter. Paths are specified in the same format as in rf-aces sf files, as a
//string of 'L' and 'R'. Nodes must be added from the root up as the case where
//the path specifies a node whose parent does not already exist in the tree is
//not handled well.
func (t *Tree) AddNode(path string, pred string, splitter *Splitter) {
	n := new(Node)
	n.Pred = pred
	n.Splitter = splitter
	if t.Root == nil {
		t.Root = n
	} else {
		loc := t.Root
		for i := 0; i < len(path); i++ {
			switch path[i : i+1] {
			case "L":
				if loc.Left == nil {
					loc.Left = n
				}
				loc = loc.Left
			case "R":
				if loc.Right == nil {
					loc.Right = n
				}
				loc = loc.Right

			case "M":
				if loc.Missing == nil {
					loc.Missing = n
				}
				loc = loc.Missing
			}

		}
	}

}

func (t *Tree) StripCodes() {
	t.Root.Climb(func(n *Node) {
		if n.CodedSplit != nil {
			n.CodedSplit = nil

		}
	})
}

/*
tree.Grow grows the receiver tree through recursion. It uses impurity decrease to select splitters at
each node as in Brieman's Random Forest. It should be called on a tree with only a root node defined.

fm is a feature matrix of training data.

target is the feature to predict via regression or classification as determined by feature type.

cases specifies the cases to calculate impurity decrease over and can contain repeated values
to allow for sampling of cases with replacement as in RF.

canidates specifies the potential features to use as splitters

mTry specifies the number of candidate features to evaluate for each split.

leafSize specifies the minimum number of cases at a leafNode.

splitmissing indicates if missing values should be split onto a third branch

vet indicates if splits should be penalized against a randomized version of them selves
*/
func (t *Tree) Grow(fm *FeatureMatrix,
	target Target,
	cases []int,
	candidates []int,
	oob []int,
	mTry int,
	leafSize int,
	splitmissing bool,
	force bool,
	vet bool,
	evaloob bool,
	importance *[]*RunningMean,
	depthUsed *[]int,
	allocs *BestSplitAllocs) {

	//var innercanidates []int
	var impDec float64
	// for i := 0; i < len(allocs.Weights); i++ {
	// 	allocs.Weights[i] = 0
	// }
	// allocs.Cases = allocs.Cases[0:0]
	// for _, i := range cases {
	// 	if allocs.Weights[i] == 0 {
	// 		allocs.Cases = append(allocs.Cases, i)
	// 	}
	// 	allocs.Weights[i]++
	// }
	t.Root.CodedRecurse(func(n *Node, innercases *[]int, depth int, nconstantsbefore int) (fi int, split interface{}, nconstants int) {

		nconstants = nconstantsbefore

		if (2 * leafSize) <= len(*innercases) {
			//SampleFirstN(&candidates, &innercanidates, mTry, 0)
			//innercanidates = candidates[:mTry]

			fi, split, impDec, nconstants = fm.BestSplitter(target, innercases, &candidates, mTry, &oob, leafSize, force, vet, evaloob, allocs, nconstantsbefore)

			// for i := mTry; i < len(candidates)-1 && impDec == minImp; i++ {
			// 	randi := i + rand.Intn(len(candidates)-i)
			// 	candidates[randi], candidates[i] = candidates[i], candidates[randi]
			// 	innercanidates = candidates[i : i+1]
			// 	fi, split, impDec, nconstants = fm.BestSplitter(target, innercases, &innercanidates, &oob, leafSize, vet, evaloob, allocs, nconstantsbefore)
			// }
			if split != nil {
				if importance != nil {
					(*importance)[fi].Add(impDec)
				}
				if depthUsed != nil && ((*depthUsed)[fi] == 0 || depth < (*depthUsed)[fi]) {
					(*depthUsed)[fi] = depth
				}
				//not a leaf node so define the splitter and left and right nodes
				//so recursion will continue
				n.CodedSplit = split
				n.Featurei = fi
				n.Splitter = fm.Data[fi].DecodeSplit(split)
				n.Pred = ""
				//is this check needed? is it safe to reuse?
				if n.Left == nil || n.Right == nil {
					n.Left = new(Node)
					n.Right = new(Node)
				}
				if splitmissing {
					n.Missing = new(Node)
				}
				return
			}

		}
		//fmt.Println("Terminating in tree grow.")

		//Leaf node so find the predictive value and set it in n.Pred
		split = nil
		n.CodedSplit = nil
		n.Splitter = nil
		n.Pred = target.FindPredicted(*innercases)
		return

	}, fm, &cases, 0, 0)
}

//GetLeaves is called by the leaf count utility to
//gather statistics about the nodes of a tree including the sets of cases at
//"leaf" nodes that aren't split further and the number of times each feature
//is used to split away each case.
func (t *Tree) GetLeaves(fm *FeatureMatrix, fbycase *SparseCounter) []Leaf {
	leaves := make([]Leaf, 0)
	ncases := fm.Data[0].Length()
	cases := make([]int, 0, ncases)
	for i := 0; i < ncases; i++ {
		cases = append(cases, i)
	}

	t.Root.Recurse(func(n *Node, cases []int, depth int) {
		if n.Left == nil && n.Right == nil { // I'm in a leaf node
			leaves = append(leaves, Leaf{cases, n.Pred})
		}
		if fbycase != nil && n.Splitter != nil { //I'm not in a leaf node?
			for _, c := range cases {
				fbycase.Add(c, fm.Map[n.Splitter.Feature], 1)
			}
		}

	}, fm, cases, 0)
	return leaves

}

func (t *Tree) Partition(fm *FeatureMatrix) *[][]int {
	leaves := make([][]int, 0)
	ncases := fm.Data[0].Length()
	cases := make([]int, 0, ncases)
	for i := 0; i < ncases; i++ {
		cases = append(cases, i)
	}

	t.Root.Recurse(func(n *Node, cases []int, depth int) {
		if n.Left == nil && n.Right == nil { // I'm in a leaf node
			leaves = append(leaves, cases)
		}

	}, fm, cases, 0)
	return &leaves

}

//Leaf is a struct for storing the index of the cases at a terminal "Leaf" node
//along with the Numeric predicted value.
type Leaf struct {
	Cases []int
	Pred  string
}

//Tree.Vote casts a vote for the predicted value of each case in fm *FeatureMatrix.
//into bb *BallotBox. Since BallotBox is not thread safe trees should not vote
//into the same BallotBox in parallel.
func (t *Tree) Vote(fm *FeatureMatrix, bb VoteTallyer) {
	ncases := fm.Data[0].Length()
	cases := make([]int, 0, ncases)
	for i := 0; i < ncases; i++ {
		cases = append(cases, i)
	}

	t.VoteCases(fm, bb, cases)
}

//Tree.VoteCases casts a vote for the predicted value of each case in fm *FeatureMatrix.
//into bb *BallotBox. Since BallotBox is not thread safe trees should not vote
//into the same BallotBox in parallel.
func (t *Tree) VoteCases(fm *FeatureMatrix, bb VoteTallyer, cases []int) {

	weight := 1.0
	if t.Weight >= 0.0 {
		weight = t.Weight
	}

	t.Root.Recurse(func(n *Node, cases []int, depth int) {
		if n.Left == nil && n.Right == nil {
			// I'm in a leaf node
			for i := 0; i < len(cases); i++ {
				bb.Vote(cases[i], n.Pred, weight)
			}
		}
	}, fm, cases, 0)
}
<commit_msg>tree.go comment clean up<commit_after>package CloudForest

import ()

//Tree represents a single decision tree.
type Tree struct {
	//Tree int
	Root   *Node
	Target string
	Weight float64
}

//NewTree initializes one node tree.
func NewTree() *Tree {
	return &Tree{new(Node), "", -1.0}
}

//AddNode adds a node a the specified path with the specified pred value and/or
//Splitter. Paths are specified in the same format as in rf-aces sf files, as a
//string of 'L' and 'R'. Nodes must be added from the root up as the case where
//the path specifies a node whose parent does not already exist in the tree is
//not handled well.
func (t *Tree) AddNode(path string, pred string, splitter *Splitter) {
	n := new(Node)
	n.Pred = pred
	n.Splitter = splitter
	if t.Root == nil {
		t.Root = n
	} else {
		loc := t.Root
		for i := 0; i < len(path); i++ {
			switch path[i : i+1] {
			case "L":
				if loc.Left == nil {
					loc.Left = n
				}
				loc = loc.Left
			case "R":
				if loc.Right == nil {
					loc.Right = n
				}
				loc = loc.Right

			case "M":
				if loc.Missing == nil {
					loc.Missing = n
				}
				loc = loc.Missing
			}

		}
	}

}

//StripCodes removes all of the coded splits from a tree so that it can be used on new catagorical data.
func (t *Tree) StripCodes() {
	t.Root.Climb(func(n *Node) {
		if n.CodedSplit != nil {
			n.CodedSplit = nil

		}
	})
}

/*
Grow grows the receiver tree through recursion. It uses impurity decrease to select splitters at
each node as in Brieman's Random Forest. It should be called on a tree with only a root node defined.

fm is a feature matrix of training data.

target is the feature to predict via regression or classification as determined by feature type.

cases specifies the cases to calculate impurity decrease over and can contain repeated values
to allow for sampling of cases with replacement as in RF.

canidates specifies the potential features to use as splitters

mTry specifies the number of candidate features to evaluate for each split.

leafSize specifies the minimum number of cases at a leafNode.

splitmissing indicates if missing values should be split onto a third branch

vet indicates if splits should be penalized against a randomized version of them selves
*/
func (t *Tree) Grow(fm *FeatureMatrix,
	target Target,
	cases []int,
	candidates []int,
	oob []int,
	mTry int,
	leafSize int,
	splitmissing bool,
	force bool,
	vet bool,
	evaloob bool,
	importance *[]*RunningMean,
	depthUsed *[]int,
	allocs *BestSplitAllocs) {

	//var innercanidates []int
	var impDec float64
	// for i := 0; i < len(allocs.Weights); i++ {
	// 	allocs.Weights[i] = 0
	// }
	// allocs.Cases = allocs.Cases[0:0]
	// for _, i := range cases {
	// 	if allocs.Weights[i] == 0 {
	// 		allocs.Cases = append(allocs.Cases, i)
	// 	}
	// 	allocs.Weights[i]++
	// }
	t.Root.CodedRecurse(func(n *Node, innercases *[]int, depth int, nconstantsbefore int) (fi int, split interface{}, nconstants int) {

		nconstants = nconstantsbefore

		if (2 * leafSize) <= len(*innercases) {
			//SampleFirstN(&candidates, &innercanidates, mTry, 0)
			//innercanidates = candidates[:mTry]

			fi, split, impDec, nconstants = fm.BestSplitter(target, innercases, &candidates, mTry, &oob, leafSize, force, vet, evaloob, allocs, nconstantsbefore)

			// for i := mTry; i < len(candidates)-1 && impDec == minImp; i++ {
			// 	randi := i + rand.Intn(len(candidates)-i)
			// 	candidates[randi], candidates[i] = candidates[i], candidates[randi]
			// 	innercanidates = candidates[i : i+1]
			// 	fi, split, impDec, nconstants = fm.BestSplitter(target, innercases, &innercanidates, &oob, leafSize, vet, evaloob, allocs, nconstantsbefore)
			// }
			if split != nil {
				if importance != nil {
					(*importance)[fi].Add(impDec)
				}
				if depthUsed != nil && ((*depthUsed)[fi] == 0 || depth < (*depthUsed)[fi]) {
					(*depthUsed)[fi] = depth
				}
				//not a leaf node so define the splitter and left and right nodes
				//so recursion will continue
				n.CodedSplit = split
				n.Featurei = fi
				n.Splitter = fm.Data[fi].DecodeSplit(split)
				n.Pred = ""
				//is this check needed? is it safe to reuse?
				if n.Left == nil || n.Right == nil {
					n.Left = new(Node)
					n.Right = new(Node)
				}
				if splitmissing {
					n.Missing = new(Node)
				}
				return
			}

		}
		//fmt.Println("Terminating in tree grow.")

		//Leaf node so find the predictive value and set it in n.Pred
		split = nil
		n.CodedSplit = nil
		n.Splitter = nil
		n.Pred = target.FindPredicted(*innercases)
		return

	}, fm, &cases, 0, 0)
}

//GetLeaves is called by the leaf count utility to
//gather statistics about the nodes of a tree including the sets of cases at
//"leaf" nodes that aren't split further and the number of times each feature
//is used to split away each case.
func (t *Tree) GetLeaves(fm *FeatureMatrix, fbycase *SparseCounter) []Leaf {
	leaves := make([]Leaf, 0)
	ncases := fm.Data[0].Length()
	cases := make([]int, 0, ncases)
	for i := 0; i < ncases; i++ {
		cases = append(cases, i)
	}

	t.Root.Recurse(func(n *Node, cases []int, depth int) {
		if n.Left == nil && n.Right == nil { // I'm in a leaf node
			leaves = append(leaves, Leaf{cases, n.Pred})
		}
		if fbycase != nil && n.Splitter != nil { //I'm not in a leaf node?
			for _, c := range cases {
				fbycase.Add(c, fm.Map[n.Splitter.Feature], 1)
			}
		}

	}, fm, cases, 0)
	return leaves

}

//Partition partitions all of the cases in a FeatureMatrix.
func (t *Tree) Partition(fm *FeatureMatrix) *[][]int {
	leaves := make([][]int, 0)
	ncases := fm.Data[0].Length()
	cases := make([]int, 0, ncases)
	for i := 0; i < ncases; i++ {
		cases = append(cases, i)
	}

	t.Root.Recurse(func(n *Node, cases []int, depth int) {
		if n.Left == nil && n.Right == nil { // I'm in a leaf node
			leaves = append(leaves, cases)
		}

	}, fm, cases, 0)
	return &leaves

}

//Leaf is a struct for storing the index of the cases at a terminal "Leaf" node
//along with the Numeric predicted value.
type Leaf struct {
	Cases []int
	Pred  string
}

//Vote casts a vote for the predicted value of each case in fm *FeatureMatrix.
//into bb *BallotBox. Since BallotBox is not thread safe trees should not vote
//into the same BallotBox in parallel.
func (t *Tree) Vote(fm *FeatureMatrix, bb VoteTallyer) {
	ncases := fm.Data[0].Length()
	cases := make([]int, 0, ncases)
	for i := 0; i < ncases; i++ {
		cases = append(cases, i)
	}

	t.VoteCases(fm, bb, cases)
}

//VoteCases casts a vote for the predicted value of each case in fm *FeatureMatrix.
//into bb *BallotBox. Since BallotBox is not thread safe trees should not vote
//into the same BallotBox in parallel.
func (t *Tree) VoteCases(fm *FeatureMatrix, bb VoteTallyer, cases []int) {

	weight := 1.0
	if t.Weight >= 0.0 {
		weight = t.Weight
	}

	t.Root.Recurse(func(n *Node, cases []int, depth int) {
		if n.Left == nil && n.Right == nil {
			// I'm in a leaf node
			for i := 0; i < len(cases); i++ {
				bb.Vote(cases[i], n.Pred, weight)
			}
		}
	}, fm, cases, 0)
}
<|endoftext|>


<commit_before>package trek

import (
	"database/sql"
	"errors"
	"reflect"
	"sort"
)

var (
	migrations                   []migration
	errNoRows                    = errors.New("sql: no rows in result set")
	errUnrecognizedDatabase      = errors.New("trek: unrecognized database")
	errUnrecognizedAction        = errors.New("trek: unrecognized action")
	errPreviousMigrationNotFound = errors.New("trek: previous migration not found")
)

const (
	// UP migrates the database to the latest version
	UP = "up"
	// DOWN migrates the database to a previous version
	DOWN = "down"
	// POSTGRES is a supported database
	POSTGRES = "postgres"
	// MYSQL is a supported database
	MYSQL = "mysql"
)

// Register adds migrations to be runned
func Register(version int64, up, down migrationHandler) {
	migrations = append(migrations, migration{
		Version: version,
		Up:      up,
		Down:    down,
	})
}

// Run executes database migrations
func Run(db *sql.DB, options ...interface{}) (didChange bool, newVersion int64, err error) {
	if len(migrations) == 0 {
		return
	}

	sort.Sort(byVersion(migrations))

	config := parseOptions(options)
	dtbs := &database{db, config}

	err = createTable(dtbs)
	if err != nil {
		return
	}

	oldVersion, err := getVersion(dtbs)
	if err != nil {
		return
	}

	newVersion, err = runMigrations(dtbs, oldVersion)
	didChange = oldVersion != newVersion
	return
}

func parseOptions(options []interface{}) *configuration {
	config := configuration{Action: UP, Database: POSTGRES}

	for _, opt := range options {
		value := reflect.ValueOf(opt)
		if value.Kind() == reflect.String {
			str := value.String()
			switch str {
			case UP:
			case DOWN:
				config.Action = str
				break
			case POSTGRES:
			case MYSQL:
				config.Database = str
				break
			}
		}
	}

	return &config
}

func createTable(db *database) error {
	var query string

	switch db.Database {
	case POSTGRES:
		query = `CREATE TABLE IF NOT EXISTS migrations (id SERIAL PRIMARY KEY, version BIGINT NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW())`
		break
	case MYSQL:
		query = `CREATE TABLE IF NOT EXISTS migrations (id AUTO_INCREMENT PRIMARY KEY, version BIGINT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)`
		break
	default:
		return errUnrecognizedDatabase
	}

	_, err := db.Exec(query)
	return err
}

func getVersion(db *database) (currentVersion int64, err error) {
	err = db.QueryRow(`SELECT version FROM migrations ORDER BY id DESC LIMIT 1`).Scan(&currentVersion)
	if err != nil && err.Error() == errNoRows.Error() {
		currentVersion = 0
		err = nil
	}
	return
}

func runMigrations(db *database, oldVersion int64) (newVersion int64, err error) {
	switch db.Action {
	case UP:
		newVersion, err = runUp(db, oldVersion)
		break
	case DOWN:
		newVersion, err = runDown(db, oldVersion)
		break
	default:
		err = errUnrecognizedAction
	}

	return
}

func runUp(db *database, oldVersion int64) (newVersion int64, err error) {
	for _, m := range migrations {
		if m.Version <= oldVersion {
			continue
		}

		if m.Up != nil {
			err = m.Up(db.DB)
			if err != nil {
				return
			}
		}

		err = setVersion(db, m.Version)
		if err != nil {
			return
		}

		newVersion = m.Version
	}

	return
}

func runDown(db *database, oldVersion int64) (newVersion int64, err error) {
	if oldVersion == 0 {
		return
	}

	var m *migration
	for i := len(migrations) - 1; i >= 0; i-- {
		if migrations[i].Version <= oldVersion {
			m = &migrations[i]
			break
		}
	}

	if m == nil {
		err = errPreviousMigrationNotFound
		return
	}

	if m.Down != nil {
		err = m.Down(db.DB)
		if err != nil {
			return
		}
	}

	newVersion = m.Version - 1
	err = setVersion(db, newVersion)
	return
}

func setVersion(db *database, version int64) error {
	var query string

	switch db.Database {
	case POSTGRES:
		query = `INSERT INTO migrations (version) VALUES ($1)`
		break
	case MYSQL:
		query = `INSERT INTO migrations (version) VALUES (?)`
		break
	default:
		return errUnrecognizedDatabase
	}

	stmt, err := db.Prepare(query)
	if err != nil {
		return err
	}

	_, err = stmt.Exec(version)
	return err
}

type migrationHandler func(*sql.DB) error

type configuration struct {
	Action   string
	Database string
}

type database struct {
	*sql.DB
	*configuration
}

type migration struct {
	Version int64
	Up      migrationHandler
	Down    migrationHandler
}

type byVersion []migration

func (s byVersion) Len() int { return len(s) }

func (s byVersion) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

func (s byVersion) Less(i, j int) bool { return s[i].Version < s[j].Version }
<commit_msg>Fix MySQL create table statement<commit_after>package trek

import (
	"database/sql"
	"errors"
	"reflect"
	"sort"
)

var (
	migrations                   []migration
	errNoRows                    = errors.New("sql: no rows in result set")
	errUnrecognizedDatabase      = errors.New("trek: unrecognized database")
	errUnrecognizedAction        = errors.New("trek: unrecognized action")
	errPreviousMigrationNotFound = errors.New("trek: previous migration not found")
)

const (
	// UP migrates the database to the latest version
	UP = "up"
	// DOWN migrates the database to a previous version
	DOWN = "down"
	// POSTGRES is a supported database
	POSTGRES = "postgres"
	// MYSQL is a supported database
	MYSQL = "mysql"
)

// Register adds migrations to be runned
func Register(version int64, up, down migrationHandler) {
	migrations = append(migrations, migration{
		Version: version,
		Up:      up,
		Down:    down,
	})
}

// Run executes database migrations
func Run(db *sql.DB, options ...interface{}) (didChange bool, newVersion int64, err error) {
	if len(migrations) == 0 {
		return
	}

	sort.Sort(byVersion(migrations))

	config := parseOptions(options)
	dtbs := &database{db, config}

	err = createTable(dtbs)
	if err != nil {
		return
	}

	oldVersion, err := getVersion(dtbs)
	if err != nil {
		return
	}

	newVersion, err = runMigrations(dtbs, oldVersion)
	didChange = oldVersion != newVersion
	return
}

func parseOptions(options []interface{}) *configuration {
	config := configuration{Action: UP, Database: POSTGRES}

	for _, opt := range options {
		value := reflect.ValueOf(opt)
		if value.Kind() == reflect.String {
			str := value.String()
			switch str {
			case UP:
			case DOWN:
				config.Action = str
				break
			case POSTGRES:
			case MYSQL:
				config.Database = str
				break
			}
		}
	}

	return &config
}

func createTable(db *database) error {
	var query string

	switch db.Database {
	case POSTGRES:
		query = `CREATE TABLE IF NOT EXISTS migrations (id SERIAL PRIMARY KEY, version BIGINT NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW())`
		break
	case MYSQL:
		query = `CREATE TABLE IF NOT EXISTS migrations (id BIGINT PRIMARY KEY AUTO_INCREMENT, version BIGINT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)`
		break
	default:
		return errUnrecognizedDatabase
	}

	_, err := db.Exec(query)
	return err
}

func getVersion(db *database) (currentVersion int64, err error) {
	err = db.QueryRow(`SELECT version FROM migrations ORDER BY id DESC LIMIT 1`).Scan(&currentVersion)
	if err != nil && err.Error() == errNoRows.Error() {
		currentVersion = 0
		err = nil
	}
	return
}

func runMigrations(db *database, oldVersion int64) (newVersion int64, err error) {
	switch db.Action {
	case UP:
		newVersion, err = runUp(db, oldVersion)
		break
	case DOWN:
		newVersion, err = runDown(db, oldVersion)
		break
	default:
		err = errUnrecognizedAction
	}

	return
}

func runUp(db *database, oldVersion int64) (newVersion int64, err error) {
	for _, m := range migrations {
		if m.Version <= oldVersion {
			continue
		}

		if m.Up != nil {
			err = m.Up(db.DB)
			if err != nil {
				return
			}
		}

		err = setVersion(db, m.Version)
		if err != nil {
			return
		}

		newVersion = m.Version
	}

	return
}

func runDown(db *database, oldVersion int64) (newVersion int64, err error) {
	if oldVersion == 0 {
		return
	}

	var m *migration
	for i := len(migrations) - 1; i >= 0; i-- {
		if migrations[i].Version <= oldVersion {
			m = &migrations[i]
			break
		}
	}

	if m == nil {
		err = errPreviousMigrationNotFound
		return
	}

	if m.Down != nil {
		err = m.Down(db.DB)
		if err != nil {
			return
		}
	}

	newVersion = m.Version - 1
	err = setVersion(db, newVersion)
	return
}

func setVersion(db *database, version int64) error {
	var query string

	switch db.Database {
	case POSTGRES:
		query = `INSERT INTO migrations (version) VALUES ($1)`
		break
	case MYSQL:
		query = `INSERT INTO migrations (version) VALUES (?)`
		break
	default:
		return errUnrecognizedDatabase
	}

	stmt, err := db.Prepare(query)
	if err != nil {
		return err
	}

	_, err = stmt.Exec(version)
	return err
}

type migrationHandler func(*sql.DB) error

type configuration struct {
	Action   string
	Database string
}

type database struct {
	*sql.DB
	*configuration
}

type migration struct {
	Version int64
	Up      migrationHandler
	Down    migrationHandler
}

type byVersion []migration

func (s byVersion) Len() int { return len(s) }

func (s byVersion) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

func (s byVersion) Less(i, j int) bool { return s[i].Version < s[j].Version }
<|endoftext|>


<commit_before>package router

import (
	"net/url"
	"strings"
)

type node struct {
	children []*node
	key      string
	param    bool
	handlers map[string][]Handler
}

func NewNode() *node {
	return &node{key: "", param: false, handlers: make(map[string][]Handler)}
}

func (n *node) Add(method, path string, handlers ...Handler) {
	i := 0
	if path[0] == '/' {
		i = 1
	}
	keys := strings.Split(path[i:], "/")
	count := len(keys)
	for {
		child, key := n.Find(path[i:], nil)
		if child.key == key && count == 1 {
			child.handlers[method] = handlers
			return
		}
		param := false
		if len(key) > 0 && key[0] == ':' {
			param = true
		}
		infant := node{key: key, param: param, handlers: make(map[string][]Handler)}
		if count == 1 {
			infant.handlers[method] = handlers
		}
		child.children = append(child.children, &infant)
		count--
		if count == 0 {
			break
		}
	}
}

func (n *node) Find(path string, params url.Values) (*node, string) {
	keys := strings.Split(path, "/")
	if len(n.children) == 0 {
		return n, keys[0]
	}
	return n.search(path, params)
}

func (n *node) search(path string, params url.Values) (*node, string) {
	keys := strings.Split(path, "/")
	for _, child := range n.children {
		if keys[0] != child.key && child.param == false {
			continue
		}
		if child.param && params != nil {
			params.Add(child.key[1:], keys[0])
		}
		next := strings.Join(keys[1:], "/")
		if len(next) > 0 {
			return child.Find(next, params)
		}
		return child, keys[0]
	}
	return n, keys[0]
}
<commit_msg>combined Find and search function for clarity<commit_after>package router

import (
	"net/url"
	"strings"
)

type node struct {
	children []*node
	key      string
	param    bool
	handlers map[string][]Handler
}

func NewNode() *node {
	return &node{key: "", param: false, handlers: make(map[string][]Handler)}
}

func (n *node) Add(method, path string, handlers ...Handler) {
	i := 0
	if path[0] == '/' {
		i = 1
	}
	keys := strings.Split(path[i:], "/")
	count := len(keys)
	for {
		child, key := n.Find(path[i:], nil)
		if child.key == key && count == 1 {
			child.handlers[method] = handlers
			return
		}
		param := false
		if len(key) > 0 && key[0] == ':' {
			param = true
		}
		infant := node{key: key, param: param, handlers: make(map[string][]Handler)}
		if count == 1 {
			infant.handlers[method] = handlers
		}
		child.children = append(child.children, &infant)
		count--
		if count == 0 {
			break
		}
	}
}

func (n *node) Find(path string, params url.Values) (*node, string) {
	keys := strings.Split(path, "/")
	if len(n.children) == 0 {
		return n, keys[0]
	}
	for _, child := range n.children {
		if keys[0] != child.key && child.param == false {
			continue
		}
		if child.param && params != nil {
			params.Add(child.key[1:], keys[0])
		}
		next := strings.Join(keys[1:], "/")
		if len(next) > 0 {
			return child.Find(next, params)
		}
		return child, keys[0]
	}
	return n, keys[0]
}
<|endoftext|>


<commit_before>package core

import (
	"reflect"
	"sort"
	"strings"
	"time"
)

const (
	POSTGRES = "postgres"
	SQLITE   = "sqlite3"
	MYSQL    = "mysql"
	MSSQL    = "mssql"
	ORACLE   = "oracle"
)

// xorm SQL types
type SQLType struct {
	Name           string
	DefaultLength  int
	DefaultLength2 int
}

const (
	UNKNOW_TYPE = iota
	TEXT_TYPE
	BLOB_TYPE
	TIME_TYPE
	NUMERIC_TYPE
)

func (s *SQLType) IsType(st int) bool {
	if t, ok := SqlTypes[s.Name]; ok && t == st {
		return true
	}
	return false
}

func (s *SQLType) IsText() bool {
	return s.IsType(TEXT_TYPE)
}

func (s *SQLType) IsBlob() bool {
	return s.IsType(BLOB_TYPE)
}

func (s *SQLType) IsTime() bool {
	return s.IsType(TIME_TYPE)
}

func (s *SQLType) IsNumeric() bool {
	return s.IsType(NUMERIC_TYPE)
}

func (s *SQLType) IsJson() bool {
	return s.Name == Json
}

var (
	Bit       = "BIT"
	TinyInt   = "TINYINT"
	SmallInt  = "SMALLINT"
	MediumInt = "MEDIUMINT"
	Int       = "INT"
	Integer   = "INTEGER"
	BigInt    = "BIGINT"

	Enum = "ENUM"
	Set  = "SET"

	Char       = "CHAR"
	Varchar    = "VARCHAR"
	NVarchar   = "NVARCHAR"
	TinyText   = "TINYTEXT"
	Text       = "TEXT"
	Clob       = "CLOB"
	MediumText = "MEDIUMTEXT"
	LongText   = "LONGTEXT"
	Uuid       = "UUID"

	Date       = "DATE"
	DateTime   = "DATETIME"
	Time       = "TIME"
	TimeStamp  = "TIMESTAMP"
	TimeStampz = "TIMESTAMPZ"

	Decimal = "DECIMAL"
	Numeric = "NUMERIC"

	Real   = "REAL"
	Float  = "FLOAT"
	Double = "DOUBLE"

	Binary     = "BINARY"
	VarBinary  = "VARBINARY"
	TinyBlob   = "TINYBLOB"
	Blob       = "BLOB"
	MediumBlob = "MEDIUMBLOB"
	LongBlob   = "LONGBLOB"
	Bytea      = "BYTEA"

	Bool = "BOOL"

	Serial    = "SERIAL"
	BigSerial = "BIGSERIAL"

	Json  = "JSON"
	Jsonb = "JSONB"

	SqlTypes = map[string]int{
		Bit:       NUMERIC_TYPE,
		TinyInt:   NUMERIC_TYPE,
		SmallInt:  NUMERIC_TYPE,
		MediumInt: NUMERIC_TYPE,
		Int:       NUMERIC_TYPE,
		Integer:   NUMERIC_TYPE,
		BigInt:    NUMERIC_TYPE,

		Enum:  TEXT_TYPE,
		Set:   TEXT_TYPE,
		Json:  TEXT_TYPE,
		Jsonb: TEXT_TYPE,

		Char:       TEXT_TYPE,
		Varchar:    TEXT_TYPE,
		NVarchar:   TEXT_TYPE,
		TinyText:   TEXT_TYPE,
		Text:       TEXT_TYPE,
		MediumText: TEXT_TYPE,
		LongText:   TEXT_TYPE,
		Uuid:       TEXT_TYPE,
		Clob:       TEXT_TYPE,

		Date:       TIME_TYPE,
		DateTime:   TIME_TYPE,
		Time:       TIME_TYPE,
		TimeStamp:  TIME_TYPE,
		TimeStampz: TIME_TYPE,

		Decimal: NUMERIC_TYPE,
		Numeric: NUMERIC_TYPE,
		Real:    NUMERIC_TYPE,
		Float:   NUMERIC_TYPE,
		Double:  NUMERIC_TYPE,

		Binary:    BLOB_TYPE,
		VarBinary: BLOB_TYPE,

		TinyBlob:   BLOB_TYPE,
		Blob:       BLOB_TYPE,
		MediumBlob: BLOB_TYPE,
		LongBlob:   BLOB_TYPE,
		Bytea:      BLOB_TYPE,

		Bool: NUMERIC_TYPE,

		Serial:    NUMERIC_TYPE,
		BigSerial: NUMERIC_TYPE,
	}

	intTypes  = sort.StringSlice{"*int", "*int16", "*int32", "*int8"}
	uintTypes = sort.StringSlice{"*uint", "*uint16", "*uint32", "*uint8"}
)

// !nashtsai! treat following var as interal const values, these are used for reflect.TypeOf comparision
var (
	c_EMPTY_STRING       string
	c_BOOL_DEFAULT       bool
	c_BYTE_DEFAULT       byte
	c_COMPLEX64_DEFAULT  complex64
	c_COMPLEX128_DEFAULT complex128
	c_FLOAT32_DEFAULT    float32
	c_FLOAT64_DEFAULT    float64
	c_INT64_DEFAULT      int64
	c_UINT64_DEFAULT     uint64
	c_INT32_DEFAULT      int32
	c_UINT32_DEFAULT     uint32
	c_INT16_DEFAULT      int16
	c_UINT16_DEFAULT     uint16
	c_INT8_DEFAULT       int8
	c_UINT8_DEFAULT      uint8
	c_INT_DEFAULT        int
	c_UINT_DEFAULT       uint
	c_TIME_DEFAULT       time.Time
)

var (
	IntType   = reflect.TypeOf(c_INT_DEFAULT)
	Int8Type  = reflect.TypeOf(c_INT8_DEFAULT)
	Int16Type = reflect.TypeOf(c_INT16_DEFAULT)
	Int32Type = reflect.TypeOf(c_INT32_DEFAULT)
	Int64Type = reflect.TypeOf(c_INT64_DEFAULT)

	UintType   = reflect.TypeOf(c_UINT_DEFAULT)
	Uint8Type  = reflect.TypeOf(c_UINT8_DEFAULT)
	Uint16Type = reflect.TypeOf(c_UINT16_DEFAULT)
	Uint32Type = reflect.TypeOf(c_UINT32_DEFAULT)
	Uint64Type = reflect.TypeOf(c_UINT64_DEFAULT)

	Float32Type = reflect.TypeOf(c_FLOAT32_DEFAULT)
	Float64Type = reflect.TypeOf(c_FLOAT64_DEFAULT)

	Complex64Type  = reflect.TypeOf(c_COMPLEX64_DEFAULT)
	Complex128Type = reflect.TypeOf(c_COMPLEX128_DEFAULT)

	StringType = reflect.TypeOf(c_EMPTY_STRING)
	BoolType   = reflect.TypeOf(c_BOOL_DEFAULT)
	ByteType   = reflect.TypeOf(c_BYTE_DEFAULT)

	TimeType = reflect.TypeOf(c_TIME_DEFAULT)
)

var (
	PtrIntType   = reflect.PtrTo(IntType)
	PtrInt8Type  = reflect.PtrTo(Int8Type)
	PtrInt16Type = reflect.PtrTo(Int16Type)
	PtrInt32Type = reflect.PtrTo(Int32Type)
	PtrInt64Type = reflect.PtrTo(Int64Type)

	PtrUintType   = reflect.PtrTo(UintType)
	PtrUint8Type  = reflect.PtrTo(Uint8Type)
	PtrUint16Type = reflect.PtrTo(Uint16Type)
	PtrUint32Type = reflect.PtrTo(Uint32Type)
	PtrUint64Type = reflect.PtrTo(Uint64Type)

	PtrFloat32Type = reflect.PtrTo(Float32Type)
	PtrFloat64Type = reflect.PtrTo(Float64Type)

	PtrComplex64Type  = reflect.PtrTo(Complex64Type)
	PtrComplex128Type = reflect.PtrTo(Complex128Type)

	PtrStringType = reflect.PtrTo(StringType)
	PtrBoolType   = reflect.PtrTo(BoolType)
	PtrByteType   = reflect.PtrTo(ByteType)

	PtrTimeType = reflect.PtrTo(TimeType)
)

func Type2SQLType(t reflect.Type) (st SQLType) {
	switch k := t.Kind(); k {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
		st = SQLType{Int, 0, 0}
	case reflect.Int64, reflect.Uint64:
		st = SQLType{BigInt, 0, 0}
	case reflect.Float32:
		st = SQLType{Float, 0, 0}
	case reflect.Float64:
		st = SQLType{Double, 0, 0}
	case reflect.Complex64, reflect.Complex128:
		st = SQLType{Varchar, 64, 0}
	case reflect.Array, reflect.Slice, reflect.Map:
		if t.Elem() == reflect.TypeOf(c_BYTE_DEFAULT) {
			st = SQLType{Blob, 0, 0}
		} else {
			st = SQLType{Text, 0, 0}
		}
	case reflect.Bool:
		st = SQLType{Bool, 0, 0}
	case reflect.String:
		st = SQLType{Varchar, 255, 0}
	case reflect.Struct:
		if t.ConvertibleTo(TimeType) {
			st = SQLType{DateTime, 0, 0}
		} else {
			// TODO need to handle association struct
			st = SQLType{Text, 0, 0}
		}
	case reflect.Ptr:
		st, _ = ptrType2SQLType(t)
	default:
		st = SQLType{Text, 0, 0}
	}
	return
}

func ptrType2SQLType(t reflect.Type) (st SQLType, has bool) {
	has = true

	switch t {
	case reflect.TypeOf(&c_EMPTY_STRING):
		st = SQLType{Varchar, 255, 0}
		return
	case reflect.TypeOf(&c_BOOL_DEFAULT):
		st = SQLType{Bool, 0, 0}
	case reflect.TypeOf(&c_COMPLEX64_DEFAULT), reflect.TypeOf(&c_COMPLEX128_DEFAULT):
		st = SQLType{Varchar, 64, 0}
	case reflect.TypeOf(&c_FLOAT32_DEFAULT):
		st = SQLType{Float, 0, 0}
	case reflect.TypeOf(&c_FLOAT64_DEFAULT):
		st = SQLType{Double, 0, 0}
	case reflect.TypeOf(&c_INT64_DEFAULT), reflect.TypeOf(&c_UINT64_DEFAULT):
		st = SQLType{BigInt, 0, 0}
	case reflect.TypeOf(&c_TIME_DEFAULT):
		st = SQLType{DateTime, 0, 0}
	case reflect.TypeOf(&c_INT_DEFAULT), reflect.TypeOf(&c_INT32_DEFAULT), reflect.TypeOf(&c_INT8_DEFAULT), reflect.TypeOf(&c_INT16_DEFAULT), reflect.TypeOf(&c_UINT_DEFAULT), reflect.TypeOf(&c_UINT32_DEFAULT), reflect.TypeOf(&c_UINT8_DEFAULT), reflect.TypeOf(&c_UINT16_DEFAULT):
		st = SQLType{Int, 0, 0}
	default:
		has = false
	}
	return
}

// default sql type change to go types
func SQLType2Type(st SQLType) reflect.Type {
	name := strings.ToUpper(st.Name)
	switch name {
	case Bit, TinyInt, SmallInt, MediumInt, Int, Integer, Serial:
		return reflect.TypeOf(1)
	case BigInt, BigSerial:
		return reflect.TypeOf(int64(1))
	case Float, Real:
		return reflect.TypeOf(float32(1))
	case Double:
		return reflect.TypeOf(float64(1))
	case Char, Varchar, NVarchar, TinyText, Text, MediumText, LongText, Enum, Set, Uuid, Clob:
		return reflect.TypeOf("")
	case TinyBlob, Blob, LongBlob, Bytea, Binary, MediumBlob, VarBinary:
		return reflect.TypeOf([]byte{})
	case Bool:
		return reflect.TypeOf(true)
	case DateTime, Date, Time, TimeStamp, TimeStampz:
		return reflect.TypeOf(c_TIME_DEFAULT)
	case Decimal, Numeric:
		return reflect.TypeOf("")
	default:
		return reflect.TypeOf("")
	}
}
<commit_msg>Support pointers to type aliases<commit_after>package core

import (
	"reflect"
	"sort"
	"strings"
	"time"
)

const (
	POSTGRES = "postgres"
	SQLITE   = "sqlite3"
	MYSQL    = "mysql"
	MSSQL    = "mssql"
	ORACLE   = "oracle"
)

// xorm SQL types
type SQLType struct {
	Name           string
	DefaultLength  int
	DefaultLength2 int
}

const (
	UNKNOW_TYPE = iota
	TEXT_TYPE
	BLOB_TYPE
	TIME_TYPE
	NUMERIC_TYPE
)

func (s *SQLType) IsType(st int) bool {
	if t, ok := SqlTypes[s.Name]; ok && t == st {
		return true
	}
	return false
}

func (s *SQLType) IsText() bool {
	return s.IsType(TEXT_TYPE)
}

func (s *SQLType) IsBlob() bool {
	return s.IsType(BLOB_TYPE)
}

func (s *SQLType) IsTime() bool {
	return s.IsType(TIME_TYPE)
}

func (s *SQLType) IsNumeric() bool {
	return s.IsType(NUMERIC_TYPE)
}

func (s *SQLType) IsJson() bool {
	return s.Name == Json
}

var (
	Bit       = "BIT"
	TinyInt   = "TINYINT"
	SmallInt  = "SMALLINT"
	MediumInt = "MEDIUMINT"
	Int       = "INT"
	Integer   = "INTEGER"
	BigInt    = "BIGINT"

	Enum = "ENUM"
	Set  = "SET"

	Char       = "CHAR"
	Varchar    = "VARCHAR"
	NVarchar   = "NVARCHAR"
	TinyText   = "TINYTEXT"
	Text       = "TEXT"
	Clob       = "CLOB"
	MediumText = "MEDIUMTEXT"
	LongText   = "LONGTEXT"
	Uuid       = "UUID"

	Date       = "DATE"
	DateTime   = "DATETIME"
	Time       = "TIME"
	TimeStamp  = "TIMESTAMP"
	TimeStampz = "TIMESTAMPZ"

	Decimal = "DECIMAL"
	Numeric = "NUMERIC"

	Real   = "REAL"
	Float  = "FLOAT"
	Double = "DOUBLE"

	Binary     = "BINARY"
	VarBinary  = "VARBINARY"
	TinyBlob   = "TINYBLOB"
	Blob       = "BLOB"
	MediumBlob = "MEDIUMBLOB"
	LongBlob   = "LONGBLOB"
	Bytea      = "BYTEA"

	Bool = "BOOL"

	Serial    = "SERIAL"
	BigSerial = "BIGSERIAL"

	Json  = "JSON"
	Jsonb = "JSONB"

	SqlTypes = map[string]int{
		Bit:       NUMERIC_TYPE,
		TinyInt:   NUMERIC_TYPE,
		SmallInt:  NUMERIC_TYPE,
		MediumInt: NUMERIC_TYPE,
		Int:       NUMERIC_TYPE,
		Integer:   NUMERIC_TYPE,
		BigInt:    NUMERIC_TYPE,

		Enum:  TEXT_TYPE,
		Set:   TEXT_TYPE,
		Json:  TEXT_TYPE,
		Jsonb: TEXT_TYPE,

		Char:       TEXT_TYPE,
		Varchar:    TEXT_TYPE,
		NVarchar:   TEXT_TYPE,
		TinyText:   TEXT_TYPE,
		Text:       TEXT_TYPE,
		MediumText: TEXT_TYPE,
		LongText:   TEXT_TYPE,
		Uuid:       TEXT_TYPE,
		Clob:       TEXT_TYPE,

		Date:       TIME_TYPE,
		DateTime:   TIME_TYPE,
		Time:       TIME_TYPE,
		TimeStamp:  TIME_TYPE,
		TimeStampz: TIME_TYPE,

		Decimal: NUMERIC_TYPE,
		Numeric: NUMERIC_TYPE,
		Real:    NUMERIC_TYPE,
		Float:   NUMERIC_TYPE,
		Double:  NUMERIC_TYPE,

		Binary:    BLOB_TYPE,
		VarBinary: BLOB_TYPE,

		TinyBlob:   BLOB_TYPE,
		Blob:       BLOB_TYPE,
		MediumBlob: BLOB_TYPE,
		LongBlob:   BLOB_TYPE,
		Bytea:      BLOB_TYPE,

		Bool: NUMERIC_TYPE,

		Serial:    NUMERIC_TYPE,
		BigSerial: NUMERIC_TYPE,
	}

	intTypes  = sort.StringSlice{"*int", "*int16", "*int32", "*int8"}
	uintTypes = sort.StringSlice{"*uint", "*uint16", "*uint32", "*uint8"}
)

// !nashtsai! treat following var as interal const values, these are used for reflect.TypeOf comparision
var (
	c_EMPTY_STRING       string
	c_BOOL_DEFAULT       bool
	c_BYTE_DEFAULT       byte
	c_COMPLEX64_DEFAULT  complex64
	c_COMPLEX128_DEFAULT complex128
	c_FLOAT32_DEFAULT    float32
	c_FLOAT64_DEFAULT    float64
	c_INT64_DEFAULT      int64
	c_UINT64_DEFAULT     uint64
	c_INT32_DEFAULT      int32
	c_UINT32_DEFAULT     uint32
	c_INT16_DEFAULT      int16
	c_UINT16_DEFAULT     uint16
	c_INT8_DEFAULT       int8
	c_UINT8_DEFAULT      uint8
	c_INT_DEFAULT        int
	c_UINT_DEFAULT       uint
	c_TIME_DEFAULT       time.Time
)

var (
	IntType   = reflect.TypeOf(c_INT_DEFAULT)
	Int8Type  = reflect.TypeOf(c_INT8_DEFAULT)
	Int16Type = reflect.TypeOf(c_INT16_DEFAULT)
	Int32Type = reflect.TypeOf(c_INT32_DEFAULT)
	Int64Type = reflect.TypeOf(c_INT64_DEFAULT)

	UintType   = reflect.TypeOf(c_UINT_DEFAULT)
	Uint8Type  = reflect.TypeOf(c_UINT8_DEFAULT)
	Uint16Type = reflect.TypeOf(c_UINT16_DEFAULT)
	Uint32Type = reflect.TypeOf(c_UINT32_DEFAULT)
	Uint64Type = reflect.TypeOf(c_UINT64_DEFAULT)

	Float32Type = reflect.TypeOf(c_FLOAT32_DEFAULT)
	Float64Type = reflect.TypeOf(c_FLOAT64_DEFAULT)

	Complex64Type  = reflect.TypeOf(c_COMPLEX64_DEFAULT)
	Complex128Type = reflect.TypeOf(c_COMPLEX128_DEFAULT)

	StringType = reflect.TypeOf(c_EMPTY_STRING)
	BoolType   = reflect.TypeOf(c_BOOL_DEFAULT)
	ByteType   = reflect.TypeOf(c_BYTE_DEFAULT)

	TimeType = reflect.TypeOf(c_TIME_DEFAULT)
)

var (
	PtrIntType   = reflect.PtrTo(IntType)
	PtrInt8Type  = reflect.PtrTo(Int8Type)
	PtrInt16Type = reflect.PtrTo(Int16Type)
	PtrInt32Type = reflect.PtrTo(Int32Type)
	PtrInt64Type = reflect.PtrTo(Int64Type)

	PtrUintType   = reflect.PtrTo(UintType)
	PtrUint8Type  = reflect.PtrTo(Uint8Type)
	PtrUint16Type = reflect.PtrTo(Uint16Type)
	PtrUint32Type = reflect.PtrTo(Uint32Type)
	PtrUint64Type = reflect.PtrTo(Uint64Type)

	PtrFloat32Type = reflect.PtrTo(Float32Type)
	PtrFloat64Type = reflect.PtrTo(Float64Type)

	PtrComplex64Type  = reflect.PtrTo(Complex64Type)
	PtrComplex128Type = reflect.PtrTo(Complex128Type)

	PtrStringType = reflect.PtrTo(StringType)
	PtrBoolType   = reflect.PtrTo(BoolType)
	PtrByteType   = reflect.PtrTo(ByteType)

	PtrTimeType = reflect.PtrTo(TimeType)
)

// Type2SQLType generate SQLType acorrding Go's type
func Type2SQLType(t reflect.Type) (st SQLType) {
	switch k := t.Kind(); k {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
		st = SQLType{Int, 0, 0}
	case reflect.Int64, reflect.Uint64:
		st = SQLType{BigInt, 0, 0}
	case reflect.Float32:
		st = SQLType{Float, 0, 0}
	case reflect.Float64:
		st = SQLType{Double, 0, 0}
	case reflect.Complex64, reflect.Complex128:
		st = SQLType{Varchar, 64, 0}
	case reflect.Array, reflect.Slice, reflect.Map:
		if t.Elem() == reflect.TypeOf(c_BYTE_DEFAULT) {
			st = SQLType{Blob, 0, 0}
		} else {
			st = SQLType{Text, 0, 0}
		}
	case reflect.Bool:
		st = SQLType{Bool, 0, 0}
	case reflect.String:
		st = SQLType{Varchar, 255, 0}
	case reflect.Struct:
		if t.ConvertibleTo(TimeType) {
			st = SQLType{DateTime, 0, 0}
		} else {
			// TODO need to handle association struct
			st = SQLType{Text, 0, 0}
		}
	case reflect.Ptr:
		st = Type2SQLType(t.Elem())
	default:
		st = SQLType{Text, 0, 0}
	}
	return
}

// default sql type change to go types
func SQLType2Type(st SQLType) reflect.Type {
	name := strings.ToUpper(st.Name)
	switch name {
	case Bit, TinyInt, SmallInt, MediumInt, Int, Integer, Serial:
		return reflect.TypeOf(1)
	case BigInt, BigSerial:
		return reflect.TypeOf(int64(1))
	case Float, Real:
		return reflect.TypeOf(float32(1))
	case Double:
		return reflect.TypeOf(float64(1))
	case Char, Varchar, NVarchar, TinyText, Text, MediumText, LongText, Enum, Set, Uuid, Clob:
		return reflect.TypeOf("")
	case TinyBlob, Blob, LongBlob, Bytea, Binary, MediumBlob, VarBinary:
		return reflect.TypeOf([]byte{})
	case Bool:
		return reflect.TypeOf(true)
	case DateTime, Date, Time, TimeStamp, TimeStampz:
		return reflect.TypeOf(c_TIME_DEFAULT)
	case Decimal, Numeric:
		return reflect.TypeOf("")
	default:
		return reflect.TypeOf("")
	}
}
<|endoftext|>


<commit_before>package wedge

import (
	"fmt"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"time"
)

// Basic URL struct which holds a match, a name and a handler function
//
// match:
//     Match is a *regexp.Regexp which we will use to check incoming
//     request URLs against and return the handler on any that match
// name:
//     Name is a simple string of what the url should be referred to as
// handler:
//     Handler is a wedge.view function which we will use against any
//     requests that match `match`.
type url struct {
	match          *regexp.Regexp
	name           string
	handler        view
	viewtype       handlertype
	rawre          string
	cache_duration time.Duration
	timeout        chan bool
}

func (u *url) String() string {
	return fmt.Sprintf(
		"{\n  URL: %s\n  Handler: %s\n}", u.match, u.name,
	)
}

// Unexported method which forms as the base method to return *url values
//
// We chose to do it like this because we can have specialized methods
// which have a simply API but fill in certain blanks for this. And the
// makeurl method can have a relatively clunky API since the work will
// be done under the hood.
func makeurl(re, name string, v view, t handlertype, duration time.Duration) *url {
	match := regexp.MustCompile(re)
	timeoutchan := make(chan bool)

	// Initialize the channel and seed with a value
	// so the first request will put the response
	// into memory
	if duration < 0 {
		duration = 30 * 12 * 30 * time.Hour
	}
	if duration > 0 {
		go func() {
			timeoutchan <- true
		}()
	}

	return &url{
		match:          match,
		name:           name,
		handler:        v,
		viewtype:       t,
		rawre:          re,
		cache_duration: duration,
		timeout:        timeoutchan,
	}
}

// URL is a function which returns a *url value.
// re:
//     re is a string which will be compiled to a *regexp.Regexp
//     and will panic if the regular expression cannot be compiled
// name:
//     Name is a simple string of what the url should be referred to as
// handler:
//     Handler is a wedge.view function which we will use against any
//     requests that match `match`.
func URL(re, name string, v view, t handlertype) *url {
	return makeurl(re, name, v, t, 0)
}

// StaticFiles is a not so light wrapper around the URL function
//
// We start off receiving an 'as' string which marks the URL to which
// we match against. We then take a []string which is filepaths to all
// the locations in which an incoming file request should be checked
// against. The file is read in chunks as per the module level constant
// FileChunk.
//
// This function will return a file in a string format ready to be sent
// across the wire.
func StaticFiles(as string, paths ...string) *url {
	return makeurl(as, "Static File", func(req *http.Request) (string, int) {
		filename := req.URL.Path[len(as):]
		for _, path := range paths {
			// Prevent Directory Traversal Attacks
			if len(strings.Split(path, "..")) > 1 {
				return "", http.StatusNotFound
			}
			out_data, err := readFile(filepath.Join(path, filename))
			if err != nil {
				continue
			}
			return out_data, http.StatusOK
		}
		return "", http.StatusNotFound
	}, STATIC, -1)
}

// CacheURL returns a URL which has caching enabled for time.Duration d.
func CacheURL(re, name string, v view, t handlertype, d time.Duration) *url {
	return makeurl(re, name, v, t, d)
}

// Favicon takes a path to some file which you want to be returned when
// a request comes through for ^/favicon.ico$. By default this will cache
// for TIMEOUT * 10.
func Favicon(path string) *url {
	file, err := os.Open(path)
	if err != nil {
		panic(err)
	}
	file.Close()

	return makeurl("^/favicon.ico$", "Favicon",
		func(req *http.Request) (string, int) {
			out_data, err := readFile(path)
			if err != nil {
				return "", http.StatusNotFound
			}
			return out_data, http.StatusOK
		}, ICON, -1)
}

// Redirect is a simple method of allowing paths to be redirected to other URLs.
func Redirect(path, to string, code int) *url {
	return makeurl(path, fmt.Sprintf("Redirecting %s => %s", path, to),
		func(req *http.Request) (string, int) {
			return to, code
		}, REDIRECT, 0)
}
<commit_msg>Added Robots function. This URL receives a string and returns the correct URL object for associating that string with the robots.txt request<commit_after>package wedge

import (
	"fmt"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"time"
)

// Basic URL struct which holds a match, a name and a handler function
//
// match:
//     Match is a *regexp.Regexp which we will use to check incoming
//     request URLs against and return the handler on any that match
// name:
//     Name is a simple string of what the url should be referred to as
// handler:
//     Handler is a wedge.view function which we will use against any
//     requests that match `match`.
type url struct {
	match          *regexp.Regexp
	name           string
	handler        view
	viewtype       handlertype
	rawre          string
	cache_duration time.Duration
	timeout        chan bool
}

func (u *url) String() string {
	return fmt.Sprintf(
		"{\n  URL: %s\n  Handler: %s\n}", u.match, u.name,
	)
}

// Unexported method which forms as the base method to return *url values
//
// We chose to do it like this because we can have specialized methods
// which have a simply API but fill in certain blanks for this. And the
// makeurl method can have a relatively clunky API since the work will
// be done under the hood.
func makeurl(re, name string, v view, t handlertype, duration time.Duration) *url {
	match := regexp.MustCompile(re)
	timeoutchan := make(chan bool)

	// Initialize the channel and seed with a value
	// so the first request will put the response
	// into memory
	if duration < 0 {
		duration = 30 * 12 * 30 * time.Hour
	}
	if duration > 0 {
		go func() {
			timeoutchan <- true
		}()
	}

	return &url{
		match:          match,
		name:           name,
		handler:        v,
		viewtype:       t,
		rawre:          re,
		cache_duration: duration,
		timeout:        timeoutchan,
	}
}

// URL is a function which returns a *url value.
// re:
//     re is a string which will be compiled to a *regexp.Regexp
//     and will panic if the regular expression cannot be compiled
// name:
//     Name is a simple string of what the url should be referred to as
// handler:
//     Handler is a wedge.view function which we will use against any
//     requests that match `match`.
func URL(re, name string, v view, t handlertype) *url {
	return makeurl(re, name, v, t, 0)
}

// StaticFiles is a not so light wrapper around the URL function
//
// We start off receiving an 'as' string which marks the URL to which
// we match against. We then take a []string which is filepaths to all
// the locations in which an incoming file request should be checked
// against. The file is read in chunks as per the module level constant
// FileChunk.
//
// This function will return a file in a string format ready to be sent
// across the wire.
func StaticFiles(as string, paths ...string) *url {
	return makeurl(as, "Static File", func(req *http.Request) (string, int) {
		filename := req.URL.Path[len(as):]
		for _, path := range paths {
			// Prevent Directory Traversal Attacks
			if len(strings.Split(path, "..")) > 1 {
				return "", http.StatusNotFound
			}
			out_data, err := readFile(filepath.Join(path, filename))
			if err != nil {
				continue
			}
			return out_data, http.StatusOK
		}
		return "", http.StatusNotFound
	}, STATIC, -1)
}

// CacheURL returns a URL which has caching enabled for time.Duration d.
func CacheURL(re, name string, v view, t handlertype, d time.Duration) *url {
	return makeurl(re, name, v, t, d)
}

// Favicon takes a path to some file which you want to be returned when
// a request comes through for ^/favicon.ico$. By default this will cache
// for TIMEOUT * 10.
func Favicon(path string) *url {
	file, err := os.Open(path)
	if err != nil {
		panic(err)
	}
	file.Close()

	return makeurl("^/favicon.ico$", "Favicon",
		func(req *http.Request) (string, int) {
			out_data, err := readFile(path)
			if err != nil {
				return "", http.StatusNotFound
			}
			return out_data, http.StatusOK
		}, ICON, -1)
}

// Redirect is a simple method of allowing paths to be redirected to other URLs.
func Redirect(path, to string, code int) *url {
	return makeurl(path, fmt.Sprintf("Redirecting %s => %s", path, to),
		func(req *http.Request) (string, int) {
			return to, code
		}, REDIRECT, 0)
}

// Returns data as the robots.txt file
func Robots(data string) *url {
	return makeurl("^/robots.txt$", "Attack of the robots...robots.txt",
		func(req *http.Request) (string, int) {
			return data, http.StatusOK
		}, HTML, -1)
}
<|endoftext|>