text:
/*
 * helper types
 */
type anyFunction = (...args: any[]) => any;
type StringOrNumber = string | number | null;

type JSONObject = {
    [key: string]: TypeOrArray<StringOrNumber | boolean | JSONObject>
}

type renderHandlerOptions = {
    update?: boolean;
    line?: number;
}

type mapFunction = (key: string, value: anyFunction) => any;
type voidFunction = () => void;

type TypeOrArray<T> = T | T[];
type TypeOrString<T> = T | string;
type TypeOrPromise<T> = T | PromiseLike<T>;

declare namespace JQueryTerminal {
    type interpreterFunction = (this: JQueryTerminal, command: string, term: JQueryTerminal) => any;
    type terminalObjectFunction = (...args: (string | number | RegExp)[]) => (void | TypeOrPromise<echoValue>);
    type Interpreter = string | interpreterFunction | ObjectInterpreter;
    type ObjectInterpreter = {
        [key: string]: ObjectInterpreter | terminalObjectFunction;
    }

    type RegExpReplacementFunction = (...args: string[]) => string;
    type IterateFormattingArgument = {
        count: number,
        index: number,
        formatting: string,
        length: number,
        text: boolean,
        space: number
    };
    type IterateFormattingFunction = (data: IterateFormattingArgument) => void;

    type strings = {
        comletionParameters: string;
        wrongPasswordTryAgain: string;
        wrongPassword: string;
        ajaxAbortError: string;
        wrongArity: string;
        commandNotFound: string;
        oneRPCWithIgnore: string;
        oneInterpreterFunction: string;
        loginFunctionMissing: string;
        noTokenError: string;
        serverResponse: string;
        wrongGreetings: string;
        notWhileLogin: string;
        loginIsNotAFunction: string;
        canExitError: string;
        invalidCompletion: string;
        invalidSelector: string;
        invalidTerminalId: string;
        login: string;
        password: string;
        recursiveCall: string;
        notAString: string;
        redrawError: string;
        invalidStrings: string;
        defunctTerminal: string;
    };

    type ParsedCommand<T> = {
        command: string;
        name: string;
        args: T[];
        args_quotes: string[];
        rest: string;
    };

    type AnsiColorType = {
        black: string;
        red: string;
        green: string;
        yellow: string;
        blue: string;
        magenta: string;
        cyan: string;
        white: string;
    }

    type LessArgument = string | ((cols: number, cb: (text: string) => void) => void) | string[];

    type ParsedOptions = {
        _: string[];
        [key: string]: boolean | string | string[];
    };

    type FormatterRegExpFunction = (...args: string[]) => string;
    type FormaterRegExpReplacement = string | FormatterRegExpFunction;
    type FormatterFunctionPropsInterface = {
        __inherit__?: boolean;
        __warn__?: boolean;
        __meta__?: boolean;
    };
    type FormatterFunction = ((str: string, options?: JSONObject) => (string | [string, number])) & FormatterFunctionPropsInterface;
    type FormatterArrayOptions = {
        loop?: boolean;
        echo?: boolean;
        command?: boolean;
        prompt?: boolean;
    };

    type Formatter = [RegExp, FormaterRegExpReplacement] | [RegExp, FormaterRegExpReplacement, FormatterArrayOptions] | FormatterFunction;
    type keymapFunctionOptionalArg = (event: JQueryKeyEventObject, original?: keymapFunction) => any;

    type keymapFunction<T = JQueryTerminal> = (this: T, event: JQueryKeyEventObject, original: keymapFunctionOptionalArg) => any;
    type keymapObject<T = JQueryTerminal> = { [key: string]: keymapFunction<T> };
    type keymapObjectOptionalArg = { [key: string]: keymapFunctionOptionalArg };

    type commandsCmdFunction<T = Cmd> = (this: T, command: string) => any;
    type echoValue = string | string[] | Element | JQuery<Element> | (() => string | string[]);
    type errorArgument = string | (() => string) | PromiseLike<string>;
    type setStringFunction = (value: string) => void;
    type setEchoValueFunction = (value: TypeOrPromise<echoValue>) => void;
    type greetingsArg = ((this: JQueryTerminal, setGreeting: setEchoValueFunction) => (void | TypeOrPromise<JQueryTerminal.echoValue>)) | string | null;
    type cmdPrompt<T = Cmd> = ((this: Cmd, setPrompt: setStringFunction) => void) | string;

    type ExtendedPrompt = ((this: JQueryTerminal, setPrompt: setStringFunction) => (void | PromiseLike<string>)) | string;

    type pushOptions = {
        infiniteLogin?: boolean;
        prompt?: ExtendedPrompt;
        login?: LoginArgument;
        name?: string;
        completion?: Completion;
    }

    type historyFilterFunction = (command: string) => boolean;
    type historyFilter = null | RegExp | historyFilterFunction;

    type KeyEventHandler<T = JQueryTerminal> = (this: T, event: JQueryKeyEventObject) => (boolean | void);

    type ExceptionHandler = (this: JQueryTerminal, e: Error | TerminalException, label: string) => void;
    type processRPCResponseFunction = (this: JQueryTerminal, result: JSONObject, term: JQueryTerminal) => void;
    type ObjectWithThenMethod = {
        then: () => any;
    }
    type SetLoginCallback = (token: string) => (void | ObjectWithThenMethod);
    type LoginFunction = (username: string, password: string, cb: SetLoginCallback) => (void | ObjectWithThenMethod);

    type LoginArgument = string | boolean | JQueryTerminal.LoginFunction;

    type Completion = string[] | CompletionFunction | boolean;

    type SetComplationCallback = (complation: string[]) => void;

    type CompletionFunction = (this: JQueryTerminal, str: string, callback: SetComplationCallback) => void;

    type EchoCommandCallback = (command: string) => void;

    // all arguments are optional so you can use $.noop
    type DoubleTabFunction = (this: JQueryTerminal, str: string, matched: string[], echoCmd: () => void) => (void | boolean);

    type RPCErrorCallback = (this: JQueryTerminal, error: any) => void;

    type RequestResponseCallback = (this: JQueryTerminal, xhr: JQuery.jqXHR, json: any, term: JQueryTerminal) => void;

    type EchoEventFunction = (this: JQueryTerminal, div: JQuery<Element>) => void;
    type EventCallback = (this: JQueryTerminal, term: JQueryTerminal) => (void | boolean);

    type formatOptions = {
        linksNoReferrer?: boolean;
        anyLinks?: boolean;
        char_width?: number;
        linksNoFollow?: boolean;
        allowedAttributes: string[];
        escape: boolean;
    };

    type InterpreterItem = {
        completion: "settings" | JQueryTerminal.Completion;
        history?: boolean;
        // all other interpreters are converted to function
        interpreter: JQueryTerminal.interpreterFunction;
        keydown?: KeyEventHandler<JQueryTerminal>;
        keypress?: KeyEventHandler<JQueryTerminal>;
        mask?: boolean | string;
        infiniteLogin?: boolean;
        prompt: ExtendedPrompt;
    }

    type PushPopCallback = (this: JQueryTerminal, before: JQueryTerminal.InterpreterItem, after: JQueryTerminal.InterpreterItem, term: JQueryTerminal) => void;

    type Lines = Array<{ string: any, options: LineEchoOptions, index: number }>;

    type View = {
        focus: boolean;
        mask: string | boolean;
        prompt?: ExtendedPrompt;
        command: string;
        position: number;
        lines: Lines;
        interpreters?: Stack<InterpreterItem>;
        history: string[];
    }

    type CompleteOptions = {
        word?: boolean;
        echo?: boolean;
        escape?: boolean;
        caseSensitive?: boolean;
        echoCommand?: boolean;
        doubleTab?: DoubleTabFunction;
    }

    type LineEchoOptions = {
        exec: boolean;
        unmount: JQueryTerminal.EchoEventFunction;
        onClear: JQueryTerminal.EchoEventFunction;
        finalize: JQueryTerminal.EchoEventFunction;
        invokeMethods: boolean;
        allowedAttributes: Array<RegExp | string>;
        flush: boolean;
        formatters: boolean;
        keepWords: boolean;
        raw: boolean;
        newline?: boolean;
    }

    type EchoOptions = {
        flush?: boolean;
        raw?: boolean;
        exec?: boolean;
        invokeMethods?: boolean;
        allowedAttributes?: Array<RegExp | string>;
        unmount?: JQueryTerminal.EchoEventFunction;
        onClear?: JQueryTerminal.EchoEventFunction;
        finalize?: JQueryTerminal.EchoEventFunction;
        keepWords?: boolean;
        formatters?: boolean;
        newline?: boolean;
    }

    interface History<T = string> {
        new(name?: string, size?: number, memory?: boolean): History<T>;
        append(item: T): void;
        set(items: T[]): void;
        data(): T[];
        reset(): void;
        last(): any;
        end(): boolean;
        position(): number;
        current(): T;
        next(): T | void;
        previous(): T | void;
        clear(): void;
        enabled(): boolean;
        enable(): void;
        purge(): void;
        disable(): void;
        toggle(value?: boolean): void;
    }

    interface Stack<T> {
        new(init?: T[]): Stack<T>;
        data(): T[];
        map(fn: (item: T, index?: number) => any): any[];
        size(): number;
        pop(): null | T;
        push(): T;
        top(): T;
        clone(): Stack<T>;
    }

    interface Cycle<T> {
        new(...args: T[]): Cycle<T>;
        get(): T[];
        index(): number;
        rotate(): T | void;
        length(): number;
        remove(i: number): void;
        set(item: T): void;
        front(): void | T;
        map(fn: (item: T, index: number) => any): any[];
        forEach(fn: (item: T, index: number) => any): void;
        append(item: T): void;
    }
}

interface JQuery<TElement = HTMLElement> {
    terminal(interpreter?: TypeOrArray<JQueryTerminal.Interpreter>, options?: TerminalOptions): JQueryTerminal;
    resizer(arg: TypeOrString<anyFunction>): JQuery;
    cmd(options?: CmdOptions): Cmd;
    text_length(): number;
    caret(pos?: number): number;
    visible(): JQuery;
    hidden(): JQuery;
    // plugins
    less(text: JQueryTerminal.LessArgument, options?: {formatters?: boolean}): JQueryTerminal;
}

interface JQueryStatic {
    omap(object: { [key: string]: anyFunction }, fn: mapFunction): { [key: string]: anyFunction };
    jrpc(url: string, method: string, params: any[], success?: (json: JSONObject, status: string, jqxhr: JQuery.jqXHR) => void, error?: (jqxhr: JQuery.jqXHR, status: string) => void): void;
    terminal: JQueryTerminalStatic;
}

interface JQueryTerminalStatic {
    version: string,
    data: string;
    color_names: string[];
    defaults: {
        formatters: JQueryTerminal.Formatter[],
        strings: JQueryTerminal.strings;
        [key: string]: any;
    };
    History(name?: string, size?: number, memory?: boolean): JQueryTerminal.History<any>;
    Stack(init?: any[]): JQueryTerminal.Stack<any>;
    Cycle(...args: any[]): JQueryTerminal.Cycle<any>;
    valid_color(color: string): boolean;
    unclosed_strings(str: string): boolean;
    escape_regex(str: string): string;
    have_formatting(str: string): boolean;
    is_formatting(str: string): boolean;
    format_split(str: string): string[];
    tracking_replace(str: string, rex: RegExp, replacement: string | JQueryTerminal.RegExpReplacementFunction, position: number): [string, number];
    iterate_formatting(str: string, callback: (data: JSONObject) => void): void;
    substring(str: string, start_index: number, end_index: number): string;
    normalize(str: string): string;
    split_equal(str: string, len: number, keep_words?: boolean): string[];
    amp(str: string): string;
    encode(str: string): string;
    nested_formatting: JQueryTerminal.FormatterFunction;
    escape_formatting(str: string): string;
    /**
     * if options have position it will return [string, display_position]
     */
    apply_formatters(str: string, options: JSONObject): string | [string, number];
    format(str: string, options?: JQueryTerminal.formatOptions): string;
    escape_brackets(str: string): string;
    unescape_brackets(str: string): string;
    length(str: string): number;
    columns(arr: string[], cols: number, space: number): string;
    strip(str: string): string;
    active(): JQueryTerminal | void;
    last_id(): number;
    parse_argument(arg: string, strict?: boolean): number | RegExp | string;
    parse_arguments(str: string): Array<number | RegExp | string>;
    split_arguments(str: string): string[];
    parse_command(str: string): JQueryTerminal.ParsedCommand<number | RegExp | string>;
    split_command(str: string): JQueryTerminal.ParsedCommand<string>;
    parse_options(arg: string | string[], options?: { booleans: string[] }): JQueryTerminal.ParsedOptions;
    extended_command(term: JQueryTerminal, str: string): void;
    /**
     * formatter is an object that can be used in RegExp functions
     */
    formatter: any;
    Exception: TerminalException;
    /**
     * plugins
     */
    prism(lang: string, text: string): string;
    prism_formatters: {
        command: boolean,
        echo: boolean,
        prompt: boolean
    },
    syntax(lang: string): void;
    pipe(obj: JQueryTerminal.ObjectInterpreter): JQueryTerminal.interpreterFunction;
    // formatters
    // unix formatting
    overtyping: JQueryTerminal.FormatterFunction;
    from_ansi: JQueryTerminal.FormatterFunction;
    ansi_colors: {
        normal: JQueryTerminal.AnsiColorType;
        faited: JQueryTerminal.AnsiColorType;
        bold: JQueryTerminal.AnsiColorType;
        palette: string[];
    };
    // xml
    xml_formatter: JQueryTerminal.FormatterFunction;
}

type TerminalException = {
    new(typeOrMessage: string, message?: string, stack?: string): TerminalException;
    message: string;
    type: string;
    stack?: string;
};

type CmdOptions = {
    mask?: string | boolean;
    caseSensitiveSearch?: boolean;
    historySize?: number;
    prompt?: JQueryTerminal.cmdPrompt;
    enabled?: boolean;
    history?: boolean | "memory";
    tabs?: number;
    onPositionChange?: (position: number, display_position: number) => void;
    clickTimeout?: number;
    holdTimeout?: number;
    holdRepeatTimeout?: number;
    mobileIngoreAutoSpace?: string[];
    repeatTimeoutKeys?: string[];
    onPaste?: (this: Cmd, value: string) => TypeOrPromise<string | Blob> | void;
    width?: number;
    historyFilter?: JQueryTerminal.historyFilter;
    commands?: JQueryTerminal.commandsCmdFunction;
    char_width?: number;
    onCommandChange?: (this: Cmd, command: string) => void;
    name?: string;
    keypress?: JQueryTerminal.KeyEventHandler<Cmd>;
    keydown?: JQueryTerminal.KeyEventHandler<Cmd>;
    tabindex?: number;
    mobileDelete?: boolean;
}

type CmdOption = "mask" | "caseSensitiveSearch" | "historySize" | "prompt" | "enabled" |
    "history" | "tabs" | "onPositionChange" | "clickTimeout" | "holdTimeout" | "onPaste" |
    "holdRepeatTimeout" | "repeatTimeoutKeys" | "width" | "historyFilter" | "commands" |
    "char_width" | "onCommandChange" | "name" | "keypress" | "keydown" | "mobileDelete";

// we copy methods from jQuery to overwrite it
// see: https://github.com/Microsoft/TypeScript/issues/978
interface Cmd<TElement = HTMLElement> extends JQuery<TElement> {
    option(name: CmdOption, value: any): Cmd;
    option(name: CmdOption): any;
    name(name: string): Cmd;
    name(): string;
    purge(): Cmd;
    history(): JQueryTerminal.History<string>;
    delete(count: number, stay?: boolean): string;
    set(command: string, stay?: boolean, silent?: boolean): Cmd;
    keymap(shortcut: string, callback: JQueryTerminal.keymapFunction<Cmd>): Cmd;
    keymap(shortcut: string): JQueryTerminal.keymapFunctionOptionalArg;
    keymap(arg: JQueryTerminal.keymapObject<Cmd>): Cmd;
    keymap(): JQueryTerminal.keymapObjectOptionalArg;
    insert(value: string, stay?: boolean): Cmd;
    /* jQuery types */
    get(index: number): TElement;
    get(): TElement[];
    get<T extends string>(): T;
    commands(fn: JQueryTerminal.commandsCmdFunction): Cmd;
    commands(): JQueryTerminal.commandsCmdFunction<void>;
    destroy(): Cmd;
    invoke_key(shortcut: string): Cmd;
    column(include_prompt: boolean): number;
    prompt(prompt: JQueryTerminal.cmdPrompt): Cmd;
    prompt(last_render: true): string;
    prompt<T extends JQueryTerminal.cmdPrompt<void>>(): T;
    kill_text(): string;
    position(): JQueryCoordinates;
    position<T extends number>(): number;
    position(value: number, silent?: boolean): Cmd;
    refresh(): Cmd;
    display_position(): number;
    display_position(value: number): Cmd;
    visible(): Cmd;
    //jQuery methods
    show(duration: JQuery.Duration, easing: string, complete: (this: TElement) => void): this;
    show(duration: JQuery.Duration, easing_complete: string | ((this: TElement) => void)): this;
    show(duration_complete_options?: JQuery.Duration | ((this: TElement) => void) | JQuery.EffectsOptions<TElement>): this;
    show(): Cmd;
    // jQuery methods
    resize(handler?: JQuery.TypeEventHandler<TElement, null, TElement, TElement, 'resize'> |
        false): this;
    // jQuery Terminal method
    resize(num_chars?: number): Cmd;
    enable(): Cmd;
    isenabled(): boolean;
    disable(focus?: boolean): Cmd;
    mask(mask: boolean | string): Cmd;
    mask<T extends boolean | string>(): T;
}

type TerminalOption = "prompt" | "name" | "history" | "exit" | "clear" | "enabled" | "maskCHar" |
    "wrap" | "checkArity" | "invokeMethods" | "anyLinks" | "raw" | "keymap" | "exceptionHandler" |
    "pauseEvents" | "softPause" | "memory" | "cancelableAjax" | "processArguments" | "onCommandChange" |
    "linksNoReferrer" | "javascriptLinks" | "processRPCResponse" | "completionEscape" | "convertLinks" |
    "unixFormattingEscapeBrackets" | "extra" | "tabs" | "historySize" | "greetings" | "scrollObject" |
    "historyState" | "importHistory" | "historyFilter" | "echoCommand" | "scrollOnEcho" | "login" |
    "outputLimit" | "onAjaxError" | "pasteImage" | "scrollBottomOffset" | "wordAutocomplete" |
    "caseSensitiveAutocomplete" | "caseSensitiveSearch" | "clickTimeout" | "holdTimeout" |
    "holdRepeatTimeout" | "request" | "describe" | "onRPCError" | "doubleTab" | "completion" |
    "onInit" | "onClear" | "onBlur" | "onFocus" | "onExit" | "onTerminalChange" | "onPush" | "onPaste" |
    "onPop" | "keypress" | "keydown" | "onAfterRedraw" | "onEchoCommand" | "onFlush" | "strings" |
    "repeatTimeoutKeys" | "allowedAttributes" | "doubleTabEchoCommand" | "mobileIngoreAutoSpace" |
    "onBeforeCommand" | "onAfterCommand" | "onBeforeLogout" | "onAfterLogout" | "onBeforeLogin" |
    "onAfterLogin" | "onBeforeEcho" | "onAfterEcho" | "autocompleteMenu" | "mobileDelete" | "renderHandler" | "pipe" | "redirets";

type TerminalOptions = {
    prompt?: JQueryTerminal.ExtendedPrompt;
    name?: string;
    history?: boolean;
    exit?: boolean;
    clear?: boolean;
    enabled?: boolean;
    maskCHar?: string;
    pipe?: boolean;
    redirects?: {[key:string]: JQueryTerminal.terminalObjectFunction};
    wrap?: boolean;
    checkArity?: boolean;
    invokeMethods?: boolean;
    anyLinks?: boolean;
    raw?: boolean;
    allowedAttributes?: Array<RegExp | string>;
    tabindex?: number;
    keymap?: JQueryTerminal.keymapObject;
    exceptionHandler?: null | JQueryTerminal.ExceptionHandler;
    pauseEvents?: boolean;
    softPause?: boolean;
    memory?: boolean;
    cancelableAjax?: boolean;
    processArguments?: boolean;
    linksNoReferrer?: boolean;
    javascriptLinks?: boolean;
    processRPCResponse?: null | JQueryTerminal.processRPCResponseFunction;
    completionEscape?: boolean;
    convertLinks?: boolean;
    unixFormattingEscapeBrackets?: boolean; // provided by unix_formatting
    extra?: any;
    tabs?: number;
    historySize?: number;
    greetings?: JQueryTerminal.greetingsArg;
    scrollObject?: null | JQuery.Selector | HTMLElement | JQuery;
    historyState?: boolean;
    importHistory?: boolean;
    historyFilter?: JQueryTerminal.historyFilter;
    echoCommand?: boolean;
    scrollOnEcho?: boolean;
    login?: JQueryTerminal.LoginArgument;
    outputLimit?: number;
    pasteImage?: boolean;
    scrollBottomOffset?: boolean;
    wordAutocomplete?: boolean;
    caseSensitiveAutocomplete?: boolean;
    caseSensitiveSearch?: boolean;
    clickTimeout?: number;
    holdTimeout?: number;
    holdRepeatTimeout?: number;
    repeatTimeoutKeys?: string[];
    mobileIngoreAutoSpace?: string[];
    request?: JQueryTerminal.RequestResponseCallback;
    response?: JQueryTerminal.RequestResponseCallback;
    describe?: string | false;
    onRPCError?: JQueryTerminal.RPCErrorCallback;
    doubleTab?: JQueryTerminal.DoubleTabFunction;
    doubleTabEchoCommand?: boolean;
    completion?: JQueryTerminal.Completion;
    keypress?: JQueryTerminal.KeyEventHandler;
    keydown?: JQueryTerminal.KeyEventHandler;
    renderHandler?: (this: JQueryTerminal, obj: any, opts: renderHandlerOptions, term: JQueryTerminal) => (void | string | Element | JQuery<Element> | false);
    onAjaxError?: (this: JQueryTerminal, xhr: JQuery.jqXHR, status: string, error: string) => void;
    onFocus?: JQueryTerminal.EventCallback;
    onInit?: JQueryTerminal.EventCallback;
    onClear?: JQueryTerminal.EventCallback;
    onBlur?: JQueryTerminal.EventCallback;
    onExit?: JQueryTerminal.EventCallback;
    onPop?: JQueryTerminal.PushPopCallback;
    onTerminalChange?: JQueryTerminal.EventCallback;
    onPush?: JQueryTerminal.PushPopCallback;
    onAfterRedraw?: JQueryTerminal.EventCallback;
    onEchoCommand?: (this: JQueryTerminal, div: JQuery, command: string, term: JQueryTerminal) => void;
    onFlush?: JQueryTerminal.EventCallback;
    onPaste?: (this: JQueryTerminal, value: string) => TypeOrPromise<string | Blob> | void;
    onCommandChange?: (this: JQueryTerminal, command: string, term: JQueryTerminal) => void;
    onPositionChange?: (this: JQueryTerminal, position: number, display_position: number, term: JQueryTerminal) => void;
    onBeforeCommand?: (this: JQueryTerminal, command: string) => (boolean | void);
    onAfterCommand?: (this: JQueryTerminal, command: string) => void;
    onBeforeLogout?: (this: JQueryTerminal) => (boolean | void);
    onAfterLogout?: (this: JQueryTerminal) => void;
    onBeforeLogin?: (this: JQueryTerminal, user: string, tokenOrPass: string) => (boolean | void);
    onAfterLogin?: (this: JQueryTerminal, user: string, token: string) => void;
    onBeforeEcho?: (this: JQueryTerminal, value: JQueryTerminal.echoValue) => (boolean | void);
    onAfterEcho?: (this: JQueryTerminal, value: JQueryTerminal.echoValue) => void;
    autocompleteMenu?: boolean;
    mobileDelete?: boolean;
    strings?: JQueryTerminal.strings;
    height?: number;
}

interface JQueryTerminal<TElement = HTMLElement> extends JQuery<TElement> {
    set_command(command: string): JQueryTerminal;
    id(): number;
    clear(): JQueryTerminal;
    export_view(): JQueryTerminal.View;
    import_view(view: JQueryTerminal.View): JQueryTerminal;
    save_state(command?: string, ignore_hash?: boolean, index?: number): JQueryTerminal;
    exec(command: string, silent?: boolean, deferred?: JQuery.Deferred<void>): JQuery.Promise<void>;
    autologin(user: string, token: string, silent?: boolean): JQueryTerminal;
    // there is success and error callbacks because we call this function from terminal and auth function can
    // be created by user
    login(auth: JQueryTerminal.LoginFunction, infinite?: boolean, success?: () => void, error?: () => void): JQueryTerminal;
    settings(): any; // we use any because option types have optional values that will throw error when used
    before_cursor(word?: boolean): string;
    complete(commands: string[], options?: JQueryTerminal.CompleteOptions): boolean;
    commands(): JQueryTerminal.interpreterFunction;
    set_interpreter(interpreter: TypeOrArray<JQueryTerminal.Interpreter>, login?: JQueryTerminal.LoginArgument): JQueryTerminal;
    greetings(): JQueryTerminal;
    paused(): boolean;
    pause(): JQueryTerminal;
    resume(): JQueryTerminal;
    cols(): number;
    rows(): number;
    history(): JQueryTerminal.History<string>;
    history_state(toggle: boolean): JQueryTerminal;
    clear_history_state(): JQueryTerminal;
    next(selector?: JQuery.Selector): this;
    next(): JQueryTerminal;
    focus(handler?: JQuery.TypeEventHandler<TElement, null, TElement, TElement, 'focus'> | false): this;
    focus(toggle?: boolean): JQueryTerminal;
    freeze(toggle?: boolean): JQueryTerminal;
    frozen(): boolean;
    enable(silent?: boolean): JQueryTerminal;
    disable(silent?: boolean): JQueryTerminal;
    enabled(): boolean;
    signature(): string;
    version(): string;
    cmd(): Cmd;
    get_command(): string;
    set_command(cmd: string, silent?: boolean): JQueryTerminal;
    set_position(pos: number, relative?: boolean): JQueryTerminal;
    get_position(): number;
    insert(str: string, stay?: boolean): JQueryTerminal;
    set_prompt(prompt: JQueryTerminal.ExtendedPrompt): JQueryTerminal;
    get_prompt<T extends JQueryTerminal.ExtendedPrompt>(): T;
    set_mask(toggle?: boolean | string): JQueryTerminal;
    get_output<T extends JQueryTerminal.Lines | string[]>(raw?: boolean): T;
    resize(handler?: JQuery.TypeEventHandler<TElement, null, TElement, TElement, 'resize'> | false): this;
    resize(width?: number, height?: number): JQueryTerminal;
    refresh(): JQueryTerminal;
    flush(options?: { update?: boolean, scroll?: boolean }): JQueryTerminal;
    update(line: number, str: string, options?: JQueryTerminal.EchoOptions): JQueryTerminal;
    // options for remove_line is useless but that's how API look like
    remove_line(line: number): JQueryTerminal;
    last_index(): number;
    echo<TValue = JQueryTerminal.echoValue>(arg: TypeOrPromise<TValue>, options?: JQueryTerminal.EchoOptions): JQueryTerminal;
    error(arg: JQueryTerminal.errorArgument, options?: JQueryTerminal.EchoOptions): JQueryTerminal;
    exception<T extends Error>(e: T, label?: string): JQueryTerminal;
    scroll(handler?: JQuery.TypeEventHandler<TElement, null, TElement, TElement, 'scroll'> | false): this;
    scroll(amount: number): JQueryTerminal;
    logout(local?: boolean): JQueryTerminal;
    token<T extends string | void>(local?: boolean): T;
    set_token(token?: string, local?: boolean): JQueryTerminal;
    get_token<T extends string | void>(local?: boolean): T;
    login_name<T extends string | void>(local?: boolean): T;
    name(): string;
    prefix_name(local?: boolean): string;
    read(message: string, success?: (result: string) => void, cancel?: voidFunction): JQuery.Promise<string>;
    push(interpreter: TypeOrArray<JQueryTerminal.Interpreter>, options?: JQueryTerminal.pushOptions): JQueryTerminal;
    pop(echoCommand?: string, silent?: boolean): JQueryTerminal;
    option(options: TerminalOptions | TerminalOption, value?: any): any;
    invoke_key(shortcut: string): JQueryTerminal;
    keymap(shortcut: string, callback: JQueryTerminal.keymapFunction): JQueryTerminal;
    keymap(shortcut: string): JQueryTerminal.keymapFunctionOptionalArg;
    keymap(arg: JQueryTerminal.keymapObject): JQueryTerminal;
    keymap(): JQueryTerminal.keymapObjectOptionalArg;
    //keymap<T extends JQueryTerminal.keymapObject | JQueryTerminal.keymapFunctionOptionalArg | JQueryTerminal>(keymap?: JQueryTerminal.keymapObject | string, fn?: JQueryTerminal.keymapFunction): T;
    level(): number;
    reset(): JQueryTerminal;
    purge(): JQueryTerminal;
    destroy(): JQueryTerminal;
    scroll_to_bottom(): JQueryTerminal;
    is_bottom(): boolean;
}


text:
#region License(Apache Version 2.0)

#endregion
#region ChangeLog
/******************************************
 * 2017-10-7 OutMan Create
 *
 * ***************************************/
#endregion
using DevExpress.Utils;
using DevExpress.XtraGrid.Columns;

namespace WitsWay.Utilities.Win.Extends
{
    /// <summary>
    /// XtraGrid辅助类
    /// </summary>
    public static class GridColumnExtends
    {

        /// <summary>
        /// 固定列宽
        /// </summary>
        /// <param name="column">列</param>
        /// <param name="width">宽度</param>
        public static void FixColumnWidth(this GridColumn column, int width)
        {
            column.MaxWidth = column.MinWidth = column.Width = width;
        }

        /// <summary>
        /// 固定列宽
        /// </summary>
        /// <param name="column">列</param>
        /// <param name="width">宽度</param>
        public static void AutoColumnWidth(this GridColumn column, int width)
        {
            column.MaxWidth = 0;
            column.MinWidth = 0;
            column.Width = width;
        }

        /// <summary>
        /// 居中文字
        /// </summary>
        /// <param name="column">列</param>
        /// <param name="centerHeader">列头居中否</param>
        /// <param name="centerCell">列单元格居中否</param>
        public static void CenterText(this GridColumn column, bool centerHeader, bool centerCell)
        {
            if (centerCell)
            {
                column.AppearanceCell.TextOptions.HAlignment = HorzAlignment.Center;
            }
            if (centerHeader)
            {
                column.AppearanceHeader.TextOptions.HAlignment = HorzAlignment.Center;
            }
        }

    }
}

redpajama_set_name: RedPajamaGithub


text:
package com.jtbdevelopment.games.rest;

import com.jtbdevelopment.games.dao.AbstractPlayerRepository;
import com.jtbdevelopment.games.dao.StringToIDConverter;
import com.jtbdevelopment.games.players.AbstractPlayer;
import com.jtbdevelopment.games.rest.handlers.PlayerGamesFinderHandler;
import com.jtbdevelopment.games.rest.services.AbstractAdminServices;
import com.jtbdevelopment.games.rest.services.AbstractGameServices;
import com.jtbdevelopment.games.rest.services.AbstractPlayerServices;
import com.jtbdevelopment.games.state.AbstractMultiPlayerGame;
import com.jtbdevelopment.games.state.masking.AbstractMaskedMultiPlayerGame;
import com.jtbdevelopment.games.state.masking.MaskedGame;
import java.io.Serializable;
import java.util.List;
import java.util.stream.Collectors;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Date: 4/8/2015 Time: 10:26 PM
 */
public abstract class AbstractMultiPlayerServices<
    ID extends Serializable,
    FEATURES,
    IMPL extends AbstractMultiPlayerGame<ID, FEATURES>,
    M extends AbstractMaskedMultiPlayerGame<FEATURES>,
    P extends AbstractPlayer<ID>>
    extends AbstractPlayerServices<ID, FEATURES, IMPL, M, P> {

  private static final Logger logger = LoggerFactory.getLogger(AbstractMultiPlayerServices.class);

  private PlayerGamesFinderHandler<ID, FEATURES, IMPL, M, P> playerGamesFinderHandler;

  @SuppressWarnings("WeakerAccess")
  protected AbstractMultiPlayerServices(
      final AbstractGameServices<ID, FEATURES, IMPL, M, P> gamePlayServices,
      final AbstractPlayerRepository<ID, P> playerRepository,
      final AbstractAdminServices<ID, FEATURES, IMPL, P> adminServices,
      final StringToIDConverter<ID> stringToIDConverter,
      final PlayerGamesFinderHandler<ID, FEATURES, IMPL, M, P> playerGamesFinderHandler) {
    super(gamePlayServices, playerRepository, adminServices, stringToIDConverter);
    this.playerGamesFinderHandler = playerGamesFinderHandler;
  }

  @GET
  @Path("games")
  @Produces(MediaType.APPLICATION_JSON)
  public List gamesForPlayer() {
    List<MaskedGame> games = playerGamesFinderHandler.findGames(getPlayerID().get());
    logger.info("Found {} games", games.size());
    logger.info("IDS {}",
        games.stream().map(game -> game.getIdAsString() + "/" + game.getGamePhase())
            .collect(Collectors.joining(",")));
    return games;
  }

}


text:
/**
 * DO NOT EDIT
 *
 * This file was automatically generated by
 *   https://github.com/Polymer/gen-typescript-declarations
 *
 * To modify these typings, edit the source file(s):
 *   animations/scale-down-animation.html
 */

/// <reference path="../../polymer/types/polymer.d.ts" />
/// <reference path="../neon-animation-behavior.d.ts" />

/**
 * `<scale-down-animation>` animates the scale transform of an element from 1 to 0. By default it
 * scales in both the x and y axes.
 *
 * Configuration:
 * ```
 * {
 *   name: 'scale-down-animation',
 *   node: <node>,
 *   axis: 'x' | 'y' | '',
 *   transformOrigin: <transform-origin>,
 *   timing: <animation-timing>
 * }
 * ```
 */
interface ScaleDownAnimationElement extends Polymer.Element, Polymer.NeonAnimationBehavior {
  configure(config: any): any;
}

interface HTMLElementTagNameMap {
  "scale-down-animation": ScaleDownAnimationElement;
}


text:
module WebDriver
  module Find

    FINDERS = {
      :class             => 'ByClassName',
      :class_name        => 'ByClassName',
      :id                => 'ById',
      :link_text         => 'ByLinkText',
      :link              => 'ByLinkText',
      :partial_link_text => 'ByPartialLinkText',
      :name              => 'ByName',
      :tag_name          => 'ByTagName',
      :xpath             => 'ByXpath',
    }

    def find_element(*args)
      how, what = extract_args(args)

      unless by = FINDERS[how.to_sym]
        raise Error::UnsupportedOperationError, "Cannot find element by #{how.inspect}"
      end

      meth = "findElement#{by}"
      what = what.to_s

      bridge.send meth, ref, what
    end

    def find_elements(*args)
      how, what = extract_args(args)

      unless by = FINDERS[how.to_sym]
        raise Error::UnsupportedOperationError, "Cannot find elements by #{how.inspect}"
      end

      meth = "findElements#{by}"
      what = what.to_s

      bridge.send meth, ref, what
    end

    private

    def extract_args(args)
      case args.size
      when 2
        args
      when 1
        arg = args.first
        unless arg.respond_to?(:shift)
          raise ArgumentError, "expected #{arg.inspect}:#{arg.class} to respond to #shift"
        end

        arr = arg.shift
        unless arr.size == 2
          raise ArgumentError, "expected #{arr.inspect} to have 2 elements"
        end

        arr
      else
        raise ArgumentError, "wrong number of arguments (#{args.size} for 2)"
      end
    end

  end # Find
end # WebDriver


text:
package org.trianacode.enactment.io.handlers;

import org.trianacode.enactment.io.IoTypeHandler;
import org.trianacode.taskgraph.TaskGraphException;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * @author Andrew Harrison
 * @version 1.0.0 Oct 3, 2010
 */
public class DoubleHandler extends IoTypeHandler<Double> {
    @Override
    public String[] getKnownTypes() {
        return new String[]{"double"};
    }

    @Override
    public Double read(String type, InputStream source) throws TaskGraphException {
        if (type.equals("double")) {
            try {
                return Double.parseDouble(readAsString(source));
            } catch (Exception e) {
                throw new TaskGraphException(e);
            }
        }
        return null;
    }

    @Override
    public void write(Double d, OutputStream sink) throws TaskGraphException {
        try {
            sink.write(d.toString().getBytes("UTF-8"));
            sink.flush();
        } catch (IOException e) {
            throw new TaskGraphException(e);
        }
    }
}


text:
<?php

declare(strict_types=1);

namespace IssetBV\PushNotification\Core\Message;

use IssetBV\PushNotification\Core\Response;
use PhpOption\Option;

abstract class MessageEnvelopeAbstract implements MessageEnvelope
{
    /**
     * @var Response
     */
    private $response;
    /**
     * @var string
     */
    private $state = self::PENDING;
    /**
     * @var Message
     */
    private $message;

    public function __construct(Message $message)
    {
        $this->message = $message;
    }

    /**
     * @param string $state
     */
    public function setState(string $state)
    {
        $this->state = $state;
    }

    /**
     * @return string
     */
    public function getState(): string
    {
        return $this->state;
    }

    /**
     * @return Option<Response>
     */
    public function getResponse(): Option
    {
        return Option::fromValue($this->response);
    }

    /**
     * @param Response $response
     *
     * @return Response
     */
    public function setResponse(Response $response)
    {
        $this->response = $response;
    }

    /**
     * @return Message
     */
    public function getMessage(): Message
    {
        return $this->message;
    }
}


text:
<!DOCTYPE html>

 <title>The Tromsø Lecture</title>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>

 <textarea id="source">
class: center, middle

.title[Time Series Analyses in a Changing Climate]

.author[Shane Elipot]

.institution[The Rosenstiel School of Marine and Atmospheric Science, University of Miami]

.coauthor[Jonathan Lilly]

.institution[NorthWest Research Associates, Seattle]

.date[November 8, 2016]

.note[Sponsored by: the FP7 Integrated Infrastructure Initiative FixO3; the Horizon 2020 project ENVRIplus; the Arctic Marine Geology and Geophysics (AMGG) Research School]
.footnote[Created with [{Remark.js}](http://remarkjs.com/) using [{Markdown}](https://daringfireball.net/projects/markdown/) +  [{MathJax}](https://www.mathjax.org/)]

---
name: foreword
class: left, .toc[[✧](#toc)]

# Foreword

This Tromsø lecture is heavily based on a longer course (The Oslo Lectures) given by Jonathan M. Lilly in Oslo at the invitation of the Norwegian Research School in Climate Dynamics (ResClim), during the week May 23–27, 2016. JML's Oslo Lectures are freely available for online viewing or download at [{www.jmlilly.net/talks/oslo/index.html}](http://www.jmlilly.net/talks/oslo/index.html)

This current Tromsø lecture is available for download on my website at [{selipot.github.io}](https://selipot.github.io) under [{Talks}]().

The practical session this afternoon will be conducted using the [{Matlab}](https://www.mathworks.com/products/matlab/) computational software and the freely available Matlab toolbox **jLab** written by Jonathan Lilly and freely available [{here}](http://www.jmlilly.net/jmlsoft.html). Please download, install, and test the toolbox before the practical session.

In addition, we will be using the code and data I have made available for download in a GitHub repository [{github.com/selipot/tromso}](https://github.com/selipot/tromso).

---
name: toc
class: left, .toc[[✧](#toc)]

# Outline

1.	[Descriptive statistics (the time domain)](#timedomain)
2.	[Stationarity, non-stationarity, and trends](#stationarity)
3.	[Fourier Spectral analysis](#spectral)
4.	[Bivariate time series](#bivariate)
4.	[Epilogue](#epilogue)
4.     [Practical](#practical)

---
name: timedomain
class: center, middle, .toc[[✧](#toc)]

# 1. Descriptive Statistics (The time domain)

---
class: left, .toc[[✧](#toc)]

#  The Sample Interval

We have a sequence of `$N$` observations

`$$x_n, \quad\quad n=0,1,2,\ldots N-1$$`

which coincide with times

`$$t_n, \quad\quad n=0,1,2,\ldots N-1.$$`

The sequence `$x_n$` is called a *discrete time series*.

It is assumed that the *sample interval*,  `$\Delta_t$`, is constant

`$$t_n=n\Delta_t$$`

with the time at `$n=0$` defined to be `$0$`.  The *duration* is `$T=N\Delta_t$`.

If the sample interval in your data is not uniform,  the first processing step is to interpolate it to be so.

---
class: left, .toc[[✧](#toc)]

#  The Underlying Process

A critical assumption is that there exists some “process” `$x(t)$` that our data sequence `$x_n$` is a *sample of*:

`\[x_n=x(n\Delta_t), \quad\quad n=0,1,2,\ldots N-1.\]`

Unlike `$x_n$`,  `$x(t)$` is believed to exist for *all times*.

(i) The process `$x(t)$` exists in *continuous time*, while `$x_n$` only exists at *discrete times*.

(ii) The process `$x(t)$` exists for *all past and future* times, while `$x_n$` is only available over a certain time interval.

It is the properties of `$x(t)$` that we are trying to estimate, *based on* the available sample  `$x_n$`.

---
class: left, .toc[[✧](#toc)]
#  Measurement Noise

In reality, the measurement device and/or data processing probably introduces some artifical variability, termed *noise*.

It is more realistic to consider that the observations `$x_n$` contain samples of the process of interest, `$y(t)$`, *plus* some noise  `$\epsilon_n$`:

`\[x_n = y(n\Delta_t)+ \epsilon_n, \quad\quad n=0,1,2,\ldots N-1.\]`

This is an example of the *unobserved components model*.  This means that  we *believe* that the data is composed of *different components*, but we cannot observe these components individually.

The process `$y(t)$` is potentially obscured or degraded by the limitations of data collection in three ways:  (i) finite sample interval, (ii) finite duration, (iii) noise.

Because of this, the time series is an *imperfect* representation of the real-world processes we are trying to study.

---
class: left, .toc[[✧](#toc)]
#  Time versus Frequency

There are two complementary (opposite) points of view regarding the time series `$x_n$`.

The first regards `$x_n$` as being built up as a sequence of discrete values `$x_0,x_2,\dots x_{N-1}$`.

This is the domain of *statistics*: the mean, variance, histogram, etc.

When we look at data statistics, generally, the order in which the values are observed *doesn't matter*.

The second point of view regards `$x_n$` as being built up of sinusoids: purely periodic functions spanning the whole duration of the data.

This is the domain of *Fourier spectral analysis*.

In between these two extremes is wavelet analysis which is not covered here, see the Oslo lectures.

---
class: left, .toc[[✧](#toc)]
#  Time-Domain Statistics

A good place to start is with the very simplest tools.

The *sample mean* describes a “typical” value:

`\[\widehat{\mu}_x \equiv \frac{1}{N}\sum_{n=0}^{N-1} x_n\]`

The *sample variance* gives the spread about the mean:

`\[\widehat{\sigma}_x^2 \equiv \frac{1}{N}\sum_{n=0}^{N-1} \left(x_n-\widehat{\mu}_x\right)^2\]`

“Sample” here means that it is computed from the observed data, as opposed to being a property of the assumed underlying process `$x(t)$`. That's why we use `$\widehat{\cdot}$`.

The mean and variance are called the first two *moments* of the distribution of values associated with the process.

---
class: left, .toc[[✧](#toc)]

# Example

22-year time series of Agulhas current transport:

Sample mean `$\widehat{\mu}_x$` is -95 Sverdrup (1 Sv = $10^6$ m$^3$ s$^{-1}$)

Sample standard deviation `$\sqrt{\widehat{\sigma}^2_x}$` is 20 Sv

---
class: left, .toc[[✧](#toc)]
#  Histogram
The mean, variance, skewness, and kurtosis (seen next) describe aspects of the *histogram*: the observed distribution of data values.

Here is the histogram of *all* Agulhas Jet transport (blue), versus Gaussian noise having the same mean and variance (orange).

---

class: left, .toc[[✧](#toc)]
#  Skewness

The *skewness* describes the tendency for an *asymmetry* between positive excursions and negative excursions:

`\[\widehat{\gamma}_x \equiv \frac{1}{\widehat{\sigma}_x^3}\frac{1}{N}\sum_{n=0}^{N-1}\left(x_n-\widehat{\mu}_x\right)^3\]`

---

class: left, .toc[[✧](#toc)]
#  Kurtosis

The *kurtosis* is said to either measure *peakedness* (concentration near `$\widehat{\mu}_x$`), or a tendency for *long tails* (concentration far from `$\widehat{\mu}_x$`):

`\[\widehat{\kappa}_x \equiv \frac{1}{\widehat{\sigma}_x^4}\frac{1}{N}\sum_{n=0}^{N-1}\left(x_n-\widehat{\mu}_x\right)^4\]`

 Actually, it measures both. Kurtosis is a measure of the spread of `$x_n$` about the *two points*  `$\mu_x \pm \sigma_x$`.  This can happen *either* for peakness *or* for long tails!  .cite[See Moors (1986), “The Meaning of Kurtosis: Darlington Reexamined”.]

Because the value of kurtosis for a Gaussian process can be shown to be equal to 3, one sometimes encounters the *excess kurtosis*

`\[\tilde\kappa_x \equiv \kappa_x -3.\]`

Values of `$\tilde\kappa_x\gt 0$` mean the data is *more kurtotic*—peaked or long-tailed—than a Gaussian, while `$\tilde\kappa_x\lt 0$` means it is less so.

---

class: center, .toc[[✧](#toc)]
#  Illustration of Kurtosis

Distributions corresponding to different values of excess kurtosis.

Positive excess kurtosis corresponds to long tails and peakedness.

---
class: left, .toc[[✧](#toc)]
#  Example

`$\widehat{\gamma}_x - =0.6, \quad \widehat{\kappa}_x - 3 = 1.14$`.

Here is the histogram of *all* Agulhas Jet transport (blue), versus Gaussian noise having the same mean and variance (orange).

---
class: left, .toc[[✧](#toc)]

# Process stats vs Estimates

How can we be sure that the *sample* statistics for `$x_n$` are the statistics of the process `$x(t)$`? We can't, but we can estimate an uncertainty for our estimates, also called an *error*.

As an example recall the sample mean is  `$\widehat{\mu}_x \equiv \frac{1}{N}\sum_{n=0}^{N-1} x_n.$`

It can be shown that the theoretical variance of the sample mean is

`$$ \sigma^2_{\widehat{\mu}_x} \equiv \frac{\sigma^2_x}{N}.$$`

so that **estimates** of the *standard error of the mean* can be calculated as $\frac{\widehat{\sigma}_x}{\sqrt{N}}$. This is a general principle: abstract concepts or mathematical objects are estimated by *estimators*, which have errors (bias and variance).

---
class: left, .toc[[✧](#toc)]
# Example
Plots of `$\widehat{\mu}_x \pm \widehat{\sigma}_{{\mu}_x}$`  and `$\widehat{\sigma}_x^2$`  as a function of increasing $N$ in chronological order (blue) or reverse chronological order (orange).

---
name: stationarity
class: center, middle, , .toc[[✧](#toc)]

# 2. Stationarity vs non-stationarity, trends
---
class: center, .toc[[✧](#toc)]
#First Example

---
class: center, .toc[[✧](#toc)]
#First Example

---
class: center, .toc[[✧](#toc)]
#First Example

---
class: left, .toc[[✧](#toc)]

# Observable Features
1.  The data consists of two time series that are similar in character.
1.  Both time series present a superposition of scales and a high degree of roughness.
1.  The data seems to consist of different time periods with distinct statistical characteristics—the data is *nonstationary*.
1.  Zooming in to one particular period show regular oscillations of roughly uniform amplitude and frequency.
1.  The phasing of these show a circular polarization orbited in a counterclockwise direction.
1.  The zoomed-in plot shows a fair amount of what appears to be measurement noise superimposed on the oscillatory signal.

--

This is a record of velocities of a single surface drifter at 6-hour intervals. All Surface drifter data are freely available from the Data Assembly Center of the Global Drifter Program [{www.aoml.noaa.gov/phod/dac/}](http://www.aoml.noaa.gov/phod/dac/index.php).

---
class: center, .toc[[✧](#toc)]
#Second Example
Can you guess what this time series is?

---
class: center, .toc[[✧](#toc)]

# Second Example

---
class: left, .toc[[✧](#toc)]

# Observable Features
1. The data exhibit a very strong positive trend, roughly linear with time. Thus, this time series does not present a **mean statistics** that represents a "typical" value.
1. On top of the trend there seems to be a sinusoid-like oscillation that does not appear to change with time.
1.  The zoomed-in plot shows noise superimposed on the sinusoidal and trend processes.

--

This is a record of daily atmospheric CO$_2$ measured at Mauna Loa in Hawaii at an altitude of 3400 m. Data from Dr. Pieter Tans, NOAA/ESRL ([{www.esrl.noaa.gov/gmd/ccgg/trends/}](http://www.esrl.noaa.gov/gmd/ccgg/trends/)) and Dr. Ralph Keeling, Scripps Institution of Oceanography ([{scrippsco2.ucsd.edu}](http://scrippsco2.ucsd.edu/)).

We will investigate further this time series during the practical session this afternoon.

---
class: left, .toc[[✧](#toc)]
# Non-stationarity

The sample statistics may be changing with time because the underlying process (that is its statistics) is changing with time. The process is said to be “non-stationary”.

Sometimes we need to re-think our model for the underlying process. Let us hypothesized that the process `$x(t)$` is the sum of an unknown process $y(t)$, plus a linear trend $a$, plus noise:
`$$x(t) = y(t) + a t + \epsilon(t),$$`

--

or maybe the trend is better described as being quadratic with time because of an acceleration:
`$$x(t) = y(t) + b t^2 + a t + \epsilon(t).$$`

--

The goal is then to estimate the unknowns $a,b$, which consists of methods of analyses generally called “parametric”. It is a bit like analyzing the data in terms of its statistics (with no prior expectations) or assuming a form for the data.

---
name: spectral
class: center, middle, .toc[[✧](#toc)]

# 3. Fourier Spectral Analysis

---

class: center, .toc[[✧](#toc)]
#  Complex Fourier Series

It is possible to represent a discrete time series `$x_n$` as a sum of complex exponentials, a complex Fourier series:

`\[ x_n = \frac{1}{N \Delta_t}\sum_{m=0}^{N-1} X_m e^{i2\pi  m n/N}, \quad\quad\quad n=0,1,\ldots N-1  \]`

We leave out for now how to obtain the complex coefficients `$X_m$` ...

---
class: left, .toc[[✧](#toc)]

#  About Frequency

You will typically find two frequency notations:

`\[ \cos(2 \pi f t)\quad\quad \text{or} \quad\quad \cos(\omega t)  \]`

`$f$` is called the *cyclic* frequency.  Its units are cycles/time. Example: Hz = cycles/sec.

`$\omega = 2 \pi f$` is called the *radian* or *angular* frequency.  Its units are rad/time. The associated *period* of oscillation is `$P=1/f=2\pi/\omega$`.

As `$t$` goes from `$0$` to `$1/f = 2\pi/\omega = P$`, `$2 \pi f t$` goes from `$0$` to `$2\pi$` and `$\omega t$` goes from `$0$` to `$2\pi$`.

A very common error in Fourier analysis is mixing up cyclic and radian frequencies!

Note: neither “cycles” nor “radians” actually have any units, thus both  `$f$` and `$\omega$` have units of 1/time. However, specifying for example 'cycles per day' or 'radians per day' helps to avoid confusion.

---
class: center, .toc[[✧](#toc)]
#Review: Sinusoids

Cosine function (blue) and sine function (orange)

---
class: center, .toc[[✧](#toc)]
# Complex Exponentials, 2D

Now consider a plot `$\cos(t)$` vs. `$\sin(t)$`.

That's the same as `$  \cos(t) + i \sin( t)  = e^{i t}$`.

---
class: center, .toc[[✧](#toc)]
# Complex Exponentials, 3D

This is better seen in 3D as a *spiral* as time increases.

`\[\cos(t) + i \sin( t) = e^{i t} \]`

---
class: left, .toc[[✧](#toc)]
#  The complex Fourier series

The discrete time series `$x_n$` can written as a sum of complex exponentials:

`\[ x_n = \frac{1}{N\Delta_t}\sum_{m=0}^{N-1} X_m e^{i2\pi  m n/N} = \frac{1}{N\Delta_t}\sum_{m=0}^{N-1} X_m e^{i2\pi n \Delta_t \cdot (m/N \Delta_t)}, \quad n=0,1,\ldots N-1  \]`

--

The  `$m$`th term behaves as `$ e^{i2\pi f_m n \Delta_t} =\cos(2\pi f_m n \Delta_t) +i \sin(2\pi f_m n \Delta_t) $`, where `$f_m\equiv m/N \Delta_t$`.

Note that in the literature, `$\Delta_t$` is often set to one, and thus omitted, leading to a lot of confusion (including for me!).

The quantity `$f_m\equiv m/N \Delta_t$` is called the `$m$`th *Fourier frequency*. The *period* associated with `$f_m$` is `$1/f_m=\Delta_t N/m$`.  Thus `$m$` tells us the *number of oscillations* contained in the length `$N \Delta_t$` time series.

---
class: center, .toc[[✧](#toc)]
#  Continuous Time

`$\cos(2\pi f_m t)$` and `$\sin(2\pi f_m t)$`

`$f_m=0,$`  `$1/100,$` `$2/100,$` `$3/100\quad\quad$`  `$t=[0\ldots 100]$`

---
class: center, .toc[[✧](#toc)]
#  Discrete Time

`$\cos(2\pi f_m n \Delta_t)$` and `$\sin(2\pi f_m n \Delta_t)$`

`$f_m=0,$`  `$1/100,$` `$2/100,$` `$3/100\quad$`  `$n=0,1,2,\dots 99\quad$` `$\Delta_t = 1$`

---
class: center, .toc[[✧](#toc)]
#  The Nyquist Frequency

The single most important frequency is the *highest resolvable* frequency, the *Nyquist frequency*.

`$f^\mathcal{N} \equiv \frac{1}{2\Delta_t} = \frac{1}{2}\cdot\frac{1}{\Delta_t}\quad\quad \omega^\mathcal{N} \equiv \frac{1}{2}\cdot\frac{2\pi}{\Delta_t}=\frac{\pi}{\Delta_t}$`

The highest resolvable frequency is *half* the *sampling rate* or *one cycle per two sampling intervals*.

`$e^{i2\pi  f^{\mathcal{N}} n \Delta_t}=e^{i2\pi \cdot 1/(2\Delta_t) \cdot n\Delta_t}=e^{i\pi n} = (-1)^n = 1,-1,1,-1,\dots $`

Note that there is no “sine” component at Nyquist in the Fourier series!

---
class: center, .toc[[✧](#toc)]
#  The Rayleigh Frequency

The second most important frequency is the *lowest resolvable* frequency, the *Rayleigh frequency*.

`$f^\mathcal{R} \equiv \frac{1}{N\Delta_t}\quad\quad \omega^\mathcal{R} \equiv \frac{2\pi}{N\Delta_t}$`

The lowest resolvable frequency is one cycle over the *entire record*.
Here the sample interval `$\Delta_t=1$` and the number of points is `$N=10$`.

---
class: left, .toc[[✧](#toc)]
#  Importance of Rayleigh

The Rayleigh frequency `$f^\mathcal{R}$` is important because it gives the *spacing between* the Fourier frequencies:

`$f_0=0$`, `$f_1=\frac{1}{N\Delta_t}$`, `$f_2=\frac{2}{N\Delta_t},\ldots$` `$\quad\quad f_n=n\,f^\mathcal{R},\quad\quad f^\mathcal{R}=\frac{1}{N\Delta_t}$`

Thus, it controls the *frequency-domain resolution*. If you want to distiguish between two closely spaced peaks, you need the dataset *duration* to be sufficiently *large* so that the Rayleigh frequency is sufficiently *small*.

--

As an example, the two principal semi-diurnal tidal “species” have period of 12 h (M`$_2$`) and 12.4206012 h (S`$_2$`). The minimum record length to distinguish the two frequencies is thus

`\[N \Delta_t = \frac{1}{f^\mathcal{R}} = \frac{1}{f^{S_2} - f^{M_2}} =\frac{1}{\frac{1}{12} - \frac{1}{12.4206012}} = 354.36 \text{ hours}.\]`

---
class: left, .toc[[✧](#toc)]
# Rayleigh and Nyquist frequencies

The ratio of the Rayleigh to Nyquist frequencies tells you how many *different frequencies* you can resolve.

 `\[\frac{f^\mathcal{N}}{f^\mathcal{R}}=\frac{N\Delta_t}{2\Delta_t}=\frac{N}{2}\]`

So why do we have `$N$` frequencies in the sum for the complex Fourier series?

`\[ x_n = \frac{1}{N \Delta_t}\sum_{m=0}^{N-1} X_m e^{i2\pi  m n/N}\]`

---
class: left, .toc[[✧](#toc)]
#The Fourier Frequencies

The first few Fourier frequencies `$f_m=m/(N\Delta_t)$` are:

`\[f_0=\frac{0}{N\Delta_t},\quad f_1=\frac{1}{N\Delta_t}, \quad f_2=\frac{2}{N\Delta_t},\ldots\]`

while the last few are

`\[\ldots,f_{N-2}=\frac{N-2}{N\Delta_t}=\frac{1}{\Delta_t}-\frac{2}{N\Delta_t},\quad f_{N-1}=\frac{N-1}{N\Delta_t}=\frac{1}{\Delta_t}-\frac{1}{N\Delta_t}.\]`

But notice that the last Fourier exponential term is

`\[e^{i2\pi f_{N-1} n\Delta_t} = e^{i2\pi (N-1) n/N}=e^{i2\pi n}e^{-i2\pi n/N}=e^{-i2\pi n/N} = e^{-i2\pi f_1 n \Delta_t}\]`

because `$e^{i2\pi n}=1$` for all integers `$n$`!  Frequencies higher than the Nyquist cannot appear due to our sample rate.  Therefore, these terms instead specify terms that have a frequency *less than* the Nyquist but that rotate in the *negative* direction.
---
class: left, .toc[[✧](#toc)]
#The Fourier Frequencies

In the vicinity of `$m=N/2$`, for even `$N$`, we have

`\[f_{N/2-1}=\frac{1}{2\Delta_t}-\frac{1}{N\Delta_t},\quad f_{N/2}=\frac{1}{2\Delta_t}, \quad f_{N/2+1}=\frac{1}{2\Delta_t}+\frac{1}{N\Delta_t},\ldots\]`

but actually the first frequency higher than the Nyquist is the *highest negative frequency*:

`\[f_{N/2-1}=\frac{1}{2\Delta_t}-\frac{1}{N\Delta_t},\quad f_{N/2}=\frac{1}{2\Delta_t}, \ldots \]`

`\[f_{N/2+1} = -f_{N/2-1} =-\left(\frac{1}{2\Delta_t}-\frac{1}{N\Delta_t}\right),\ldots.\]`

Thus the positive frequencies and negative frequencies are both increasing *toward the middle* of the Fourier transform array.

For this reason Matlab provides <tt>fftshift</tt>, to shifts the zero frequency, *not* the Nyquist, to be in the middle of the array.

---
class: left, .toc[[✧](#toc)]
#One-Sided vs. Two-Sided

There exists two strictly equivalent representations,  *two-sided* and *one-sided*, of the discrete Fourier transform:

`\begin{eqnarray}
  x_n&=&\frac{1}{N\Delta_t}\sum_{m=0}^{N-1} X_m e^{i2\pi m n/N},\\
x_n&=& \frac{1}{N\Delta_t}X_0 + \frac{2}{N\Delta_t}\sum_{m=1}^{N/2-1} A_m \cos\left(2\pi m n/N +\Phi_m\right) + X_{N/2} (-1)^n,
  \end{eqnarray}`

where  `$A_m$` and  `$\Phi_m$` are an *amplitude* and *phase*, with `$X_m = A_m e^{i \Phi_m}$`.

The two-sided representation is more compact mathematically.

For real-valued `$x_n$`, the one-sided representation is more intuitive as it expresses `$x_n$` as a sum of *phase-shifted* cosinusoids.
--

A price of the one-sided form is that even and odd `$N$` are somewhat different!  The expression above is for even-valued `$N$`.

---
class: left, .toc[[✧](#toc)]
#The Forward DFT

So? How do we know the values of the Fourier coefficients `$X_m$`? It can be shown that:

`\[X_m =  \Delta_t \sum_{n=0}^{N-1}x_n e^{-i2\pi m n/N}\]`

This is called the *discrete Fourier transform* of `$x_n$`.

The DFT *transforms* `$x_n$` from the time domain to the frequency domain. The DFT *defines* a sequence of `$N$` complex-valued numbers, `$X_m$`,  for `$m=0,1,2,\ldots N-1$`, which are termed the *Fourier coefficients.*

In Matlab, the discrete Fourier transform defined above is computed by <tt>fft(x)</tt>`$\times \Delta_t $`.

---
class: left, .toc[[✧](#toc)]
#The Inverse DFT

In fact,

`\[x_n \equiv  \frac{1}{N\Delta_t}\sum_{m=0}^{N-1}X_m e^{i2\pi m n/N}\]`

is called the *inverse discrete Fourier transform.* It expresses how `$x_n$` may be *constructed* using the Fourier coefficients multiplying complex exponentials—or, as we saw earlier, phase-shifted sinusoids.

---
class: left, .toc[[✧](#toc)]
#The Spectrum

**One of several definitions** of the *spectrum*, or *spectral density function*, at frequency `$f_m$`, is:

`\[S(f_m) \equiv \lim_{N \rightarrow \infty} E\left\{ \frac{|X_m|^2}{N} \right\}.\]`

`$E\{\cdot\}$` is called the *expectation*, it is a conceptual “average” over a statistical ensemble, and it cannot obtained in practice.

--

Formally, the function `$S$` is defined for all frequencies `$f$`, not only `$f_m$`, but as `$N \rightarrow \infty$`, the Rayleigh frequency `$1/N\Delta_t$` becomes infinitesimally small, and all frequencies are obtained.

--

However, `$N \rightarrow \infty$` is not achievable ... Therefore, one aspect of spectral analysis is to find an acceptable **estimate** of the true, unknown, spectrum `$S(f)$` of the process `$x(t)$`.

---
class: left, .toc[[✧](#toc)]
#The Parseval Theorem

A very important theorem is *Parseval's theorem* which takes  the following form for the discrete case:

`\[\Delta_t \sum_{n=0}^{N-1} |x_n|^2 = \frac{1}{N\Delta_t} \sum_{m=0}^{N-1} |X_m|^2.\]`

When `$\widehat{\mu}_x=0$`, this theorem shows that the total **variance** of `$x_n$` is recoverable from the sum of absolute Fourier coefficients squared.

Which can be interpreted as saying that the spectrum gives you the distribution of the variance as a function of frequency.

---
class: left, .toc[[✧](#toc)]
#Spectral Estimates

The simplest way to estimate the *spectrum* `$S(f)$` function of frequency `$f$` is to simply take the modulus squared of the Fourier transform,
`\[\widehat{S}(f_m) = \widehat{S}_m\equiv \frac{1}{N}\left|X_m\right|^2,\quad\quad m=0, 1, 2, \ldots,(N-1).\]`
This quantity is known as the *periodogram*.

Note that the Matlab <tt>fft(x)</tt> command assumes `$\Delta_t = 1$` so you need to plot <tt>abs(fft(x))</tt>`$^2\times  \Delta_t /N$`.

As we shall see, the periodogram is *not* the spectrum!  It is an *estimate* of the spectrum—and generally speaking, a very poor one.

It is also said to be the *naive* spectral estimate, meaning it is the spectral estimate that you get if you don't know that there is something better. Please do not use the periodogram in your publications.

---
class: left, .toc[[✧](#toc)]
#The Multitaper Method

An alternate spectral estimate called the *multitaper* method.  Here is a quick sketch of this method.

We form a set of `$K$` different sequences the same length as the data, that is, having `$N$` points in time.  These sequences are chosen from a special family of functions that is closely related to familiar orthogonal functions, e.g. the Hermite functions.

These `$K$` different sequences are denoted as `$\psi_n^{\{k\}}$` for `$k=1,2,\ldots K$.`  For each of these sequence, we form a spectral estimate as

`\[\widehat S_m^{\{k\}}\equiv \left|\Delta_t \sum_{n=0}^{N-1} \psi_n x_n\, e^{-i 2\pi m n/N}\right|^2,\quad\quad n=0, 1, 2, \ldots,(N-1).\]`

which involves *multiplying* the data by the sequence `$\psi_n^{\{k\}}$` *before* taking the Fourier transform.
---
class: left, .toc[[✧](#toc)]
#The Multitaper Method

The action of multiplying the data by some sequence before Fourier transforming it, as in
`\[\widehat S_m^{\{k\}}\equiv \left|\Delta_t \sum_{n=0}^{N-1} \psi_n x_n\, e^{-i 2\pi m n/N}\right|^2,\quad\quad n=0, 1, 2, \ldots,(N-1)\]`
is called *tapering*.  The goal is to reduce the **bias** (systematic error) of the spectral estimate.
These `$K$` different individual estimates (aka *eigenspectra*), are combined into one *average* spectral estimate, in order to reduce the **variance** (random error) of the estimate

`\[\widehat S_m^{\psi}\equiv \frac{1}{K}\sum_{k=1}^K\widehat S_m^{\{k\}}.\]`

The multitaper method therefore involves two steps: (i)  *tapering* the data, and (ii) *averaging* over multiple individual spectral estimates.
---
class:center, .toc[[✧](#toc)]
#The Taper Functions

`Here $K=5$` *Slepian* tapers are shown.  These are orthogonal functions that become more oscillatory for increasing `$K$.`
---
class: left, .toc[[✧](#toc)]
#The Multitaper Method
The multitaper method controls the degrees of spectral *smoothing* and *averaging* through changing the properties of the tapers.

The multitaper method is generally the favorite spectral analysis method among those researchers who have thought the most about spectral analysis.

It is recommended because **(i)** it avoids the deficiencies of the periodogram, **(ii)** it has, in a certain sense, provable optimal properties, **(iii)** it is very easy to implement and adjust, **(iv)** it allows an estimate of the spectrum for the period equal to the length of your time series (no need to divide up your time series as for the Welch's method!).

See .cite[Thomson (1982)], .cite[Park et al. (1987)], and .cite[Percival and Walden, *Spectral Analysis for Physical Applications*].

---
class: left, .toc[[✧](#toc)]
#Example

22-year time series of Agulhas current transport

---
class: left, .toc[[✧](#toc)]
#Example: periodogram

Linear plot

---
class: left, .toc[[✧](#toc)]
#Example: periodogram

Log-log plot

---
class: left, .toc[[✧](#toc)]
#Example: multitaper

Effect of first taper

---
class: left, .toc[[✧](#toc)]
#Example: multitaper

Second taper

---
class: left, .toc[[✧](#toc)]
#Example: multitaper

Third taper

---
class: left, .toc[[✧](#toc)]
#Example: multitaper

Fourth taper

---
class: left, .toc[[✧](#toc)]
#Example: multitaper

Fifth taper

---
class: left, .toc[[✧](#toc)]
#Example: multitaper

Fifth taper

---
class: left, .toc[[✧](#toc)]
#Example: multitaper

Eigen spectra (colors) and multitaper estimate (black)

---
class: left, .toc[[✧](#toc)]
#Example: period. vs mt

Periodogram (gray) vs multitaper (black)

---

name: bivariate
class: center, middle, .toc[[✧](#toc)]

# 4. Bivariate time series

---
class: left, .toc[[✧]
#Vector and complex notations

What if your process of interest is composed of two time series, let's say `$x(t)$` and `$y(t)$`? As in the vector components of ocean currents or atmospheric winds:

`\begin{eqnarray}
\mathbf{z}(t) = \left[ \begin{matrix} x(t) \\ y(t) \end{matrix}\right]
\end{eqnarray}`

Often, a *bivariate* time series is conveniently written as a complex-valued time series:

`\[ z(t) = x(t) + i y(t) = |z(t)| e^{i \arg{(z)}},\]`

where `$i = \sqrt{-1}$` and `$\arg{(z)}$` is the *complex argument* (or polar angle) of `$z$` in the interval `$[-\pi,+\pi]$`.

---
class: left, .toc[[✧](#toc)]
#The Mean of Bivariate Data

The sample mean of the vector time series `$\mathbf{z}_n$` is also a vector,

`\[\mathbf{\mu}_\mathbf{z} \equiv \frac{1}{N}\sum_{n=0}^{N-1}\mathbf{z}_n=\begin{bmatrix} \widehat{\mu}_x \\ \,\widehat{\mu}_y\,\end{bmatrix}\]`

that consists of the *sample means* of the `$x_n$` and `$y_n$` components of `$\mathbf{z}_n$`.

---
class: left, .toc[[✧](#toc)]
#Variance of Bivariate Data

The *variance* of the vector-valued times series `$\mathbf{z}_n$` is not a scalar or a vector, it is a `$2\times 2$` *matrix*

`\[\mathbf{\Sigma}\equiv \frac{1}{N}\sum_{n=0}^{N-1}\left(\mathbf{z}_n-\mathbf{\mu}_\mathbf{z}\right)\left(\mathbf{z}_n-\mathbf{\mu}_\mathbf{z}\right)^T \]`

where “`$T$`” is the *matrix transpose*, `$\mathbf{z}_n =\begin{bmatrix} x_n \\ y_n \end{bmatrix}$`, `$\mathbf{z}_n^T  =\begin{bmatrix} x_n & y_n \end{bmatrix}$`.

Carrying out the matrix multiplication leads to

`\[\mathbf{\Sigma}= \frac{1}{N}\sum_{n=0}^{N-1}
\begin{bmatrix} \left(x_n-\widehat{\mu}_x\right)^2 & \left(x_n-\widehat{\mu}_x\right)\left(y_n-\widehat{\mu}_y\right)\\ \left(x_n-\widehat{\mu}_x\right)\left(y_n-\widehat{\mu}_y\right) &\left(y_n-\widehat{\mu}_y\right)^2 \end{bmatrix}
\]`

The diagonal elements of `$\mathbf{\Sigma}$` are the sample variances `$\sigma_x^2$` and `$\sigma_y^2$`, while the off-diagonal gives the *covariance* between `$x_n$` and `$y_n$`.  Note that the two off-diagonal elements are identical.

---
class: left, .toc[[✧](#toc)]
# Fourier transform

The Fourier theory presented earlier for *scalar* time series is completely applicable to complex-valued time series, in discrete form (`$N$` even):
`\begin{eqnarray}
z_n & =  & \frac{1}{N \Delta_t}\sum_{m=0}^{N/2} Z_m e^{i2\pi  m n/N} & + \frac{1}{N \Delta_t}\sum_{m=N/2+1}^{N-1} Z_m e^{i2\pi  m n/N}\\
 & = & \frac{1}{N \Delta_t}\sum_{m=0}^{N/2} Z^+_m e^{i2\pi  m n/N} & + \frac{1}{N \Delta_t}\sum_{m=1}^{N/2-1} Z^-_m e^{-i2\pi  m n/N}.
\end{eqnarray}`

The first sum corresponds to **positive** frequencies, and the second sum to the associated **negative** frequencies (except the zero and Nyquist frequencies for `$m=0,N/2$`).

---
class: left, .toc[[✧](#toc)]
#Rotary Spectra

`\begin{equation}
z_n  = \frac{1}{N \Delta_t}\sum_{m=0}^{N/2} Z^+_m e^{i2\pi  m n/N} + \frac{1}{N \Delta_t}\sum_{m=1}^{N/2-1} Z^-_m e^{-i2\pi  m n/N}.
\end{equation}`

This introduces the concept of *rotary spectrum*:
`\begin{eqnarray}
S(f_m>0) \equiv S^+(f_m) & \equiv & \lim_{N \rightarrow \infty} E\left\{ \frac{|Z^+_m|^2}{N} \right\}  \quad \text{counterclockwise spectrum,}\\
S(f_m<0) \equiv  S^-(-f_m) & \equiv & \lim_{N \rightarrow \infty} E\left\{ \frac{|Z^-_m|^2}{N} \right\} \quad \text{clockwise spectrum.}\\
\end{eqnarray}`
`\[f_m = \frac{m}{N\Delta_t}, \quad m = 0,\ldots,N/2\]`

This is very useful in geophysical fluid mechanics because counterclockwise motions are *cyclonic* in the northern hemisphere and clockwise motions are *anticyclonic*, and vice-versa in the southern hemisphere.

---
class: left, .toc[[✧](#toc)]
#Rotary variance

Imagine you have only two opposite components present in your time series at frequency `$f_k$`:
`\begin{eqnarray}
	 z_n & = & Z_k^+ e^{i2\pi k n /N} + Z_k^- e^{-i2\pi k n /N} \\
	 & = & \left\{A^+ e^{i \phi^+} \right\} e^{i2\pi k n /N} + \left\{A^- e^{i \phi^-}\right\}e^{-i2\pi k n /N} \\
	 & = & e^{i\theta}\left\{ A \cos (2\pi k n/N + \phi) + i B \sin(2\pi k n/N + \phi) \right\}
\end{eqnarray}`
	 where
`\begin{eqnarray}
	 \theta & = & (\phi^+-\phi^-)/2\\
	 \phi & = & (\phi^++\phi^-)/2\\
	 A&=& A^++A^-\\
	 B &= & A^+-A^-.	\\
 \end{eqnarray}`

---
class: left, .toc[[✧](#toc)]
#Elliptic variance
`\[ z_n = e^{i\theta}\left\{ A \cos (2\pi k n/N + \phi) + i B \sin(2\pi k n/N + \phi) \right\}\]`

This is the equation for an ellipse oriented at an angle `$\theta$` from the `$x$` axis, with semi-major and semi-minor axes $A$ and $B$, respectively, rotating at frequency $f_k = k/(N\Delta_t)$, in the direction given by the sign of `$B$`.

See more details about elliptic variance in JML's Oslo lectures.

---
class: left, .toc[[✧](#toc)]
#Cartesian Spectra

Rotary and Cartesian spectra are two alternate representation of the variance of the complex time series:
`\begin{equation}
z_n  = \frac{1}{N \Delta_t}\sum_{m=0}^{N/2} Z^+_m e^{i2\pi  m n/N} + \frac{1}{N \Delta_t}\sum_{m=1}^{N/2-1} Z^-_m e^{-i2\pi  m n/N}.
\end{equation}`

`\begin{equation}
\widehat{S}^+_m \equiv \frac{1}{N}\left|Z^+_m\right|^2, \quad \widehat{S}^-_m \equiv  \frac{1}{N}\left|Z^-_m\right|^2 \quad \text{Rotary spectra estimates}
\end{equation}`

`\begin{equation}
z_n  = x_n+ i y_n = \frac{1}{N \Delta_t}\sum_{m=0}^{N-1} X_m e^{i2\pi  m n/N} + i \left\{ \frac{1}{N \Delta_t}\sum_{m=0}^{N-1} Y_m e^{i2\pi  m n/N}\right\}.
\end{equation}`

`\begin{equation}
\widehat{S}^x_m \equiv \frac{1}{N}\left|X_m\right|^2, \quad \widehat{S}^y_m \equiv  \frac{1}{N}\left|Y_m\right|^2 \quad \text{Cartesian spectra estimates}
\end{equation}`

---
class: left, .toc[[✧](#toc)]
#Parseval theorem
For bivariate data, the discrete form of the Parseval theorem takes the form:
`\begin{eqnarray}
\Delta_t \sum_{n=0}^{N-1} |z_n|^2 = \frac{1}{N\Delta_t} \sum_{m=0}^{N-1} |Z_m|^2 & = & \frac{1}{N\Delta_t} \sum_{m=0}^{N-1} |X_m|^2 + \frac{1}{N\Delta_t} \sum_{m=0}^{N-1} |Y_m|^2\\
 & = & \frac{1}{N\Delta_t} \sum_{m=0}^{N/2} |Z^+_m|^2 + \frac{1}{N\Delta_t} \sum_{m=1}^{N/2-1} |Z^-_m|^2 \\
\end{eqnarray}`

--

This shows that the total variance of the bivariate process is recovered completely by the Cartesian, or rotary Fourier representation.

---
class: left, .toc[[✧](#toc)]
#Example

Hourly current meter record at 110 m depth from the Bravo mooring in the Labrador Sea, .cite[Lilly and Rhines (2002)]

---
class: left, .toc[[✧](#toc)]
#Example 1

Hourly current meter record at 110 m depth from the Bravo mooring in the Labrador Sea, .cite[Lilly and Rhines (2002)]

---
class: left, .toc[[✧](#toc)]
#Example 1

Hourly current meter record at 110 m depth from the Bravo mooring in the Labrador Sea, .cite[Lilly and Rhines (2002)]

---
class: left, .toc[[✧](#toc)]
#Observable Features
1.  The data consists of two time series that are similar in character.
1.  Both time series present a superposition of scales.
1.  At the smallest scale, there is an apparently oscillatory roughness which changes its amplitude in time.
1.  A larger scale presents itself either as localized features, or as wavelike in nature.
1.  Several sudden transitions are associated with isolated events.
1.  Zooming in, we see the small-scale oscillatory behavior is sometimes `$90^\circ$` degrees out of phase, and sometimes `$180^\circ$`.
1.  The amplitude of this oscillatory variability changes with time.

The fact that the oscillatory behavior is not consistently `$90^\circ$` out of phase removes the possibility of these features being purely inertial oscillations.  The amplitude modulation suggests tidal beating.

--

The isolated events are  eddies, which cause the currents to suddenly rotate as they pass by.  The oscillations are due to tides and internal waves.

---
class: left, .toc[[✧](#toc)]
#Cartesian vs Rotary Spectra

---
class: left, .toc[[✧](#toc)]
#Cartesian vs Rotary Spectra

---
class: left, .toc[[✧](#toc)]
#Cartesian vs Rotary Spectra

---
class: left, .toc[[✧](#toc)]
#Cartesian vs Rotary Spectra

---
class: left, .toc[[✧](#toc)]
#Example
Global zonally-averaged rotary spectra from hourly drifter velocities, see .cite[Elipot et al. 2016].

---
name: epilogue
class: left, .toc[[✧](#toc)]
#Epilogue

Many important topic of time series analyses were not discussed, namely the topics of *aliasing*, spectral blurring, filtering, and uncertainties in spectral estimates. Some of these are covered in JML's Oslo lecture which can be viewed online at [{www.jmlilly.net/talks/oslo/index.html}](http://www.jmlilly.net/talks/oslo/index.html).

During the practical session this afternoon we will cover the material presented this morning, as well cover some of the topic of filtering.

Thank you!

Shane Elipot

email: <tt>selipot@rsmas.miami.edu</tt>

The slides of this presentation are available at [{rsmas.miami.edu/users/selipot/}](http://rsmas.miami.edu) or  [{selipot.github.io}](http://selipot.github.io)

---
name: practical
class: center, middle, .toc[[✧](#toc)]
#Slides for Pratical session

---
class: left, .toc[[✧](#toc)]
# Code and Data

For the practical session this afternoon you will need some Matlab code and data to be downloaded from my GitHUb depository called *Tromso*.

[https://github.com/selipot/tromso](https://github.com/selipot/tromso).

Click on the green button “Clone or download” to download a zipped archive, expand it, and copy the directory where you want.

Please do this before coming to the session this afternoon.

---
class: left, .toc[[✧](#toc)]
#  Continuous Fourier

We have considered the FT for a discrete time series `$x_n$` but it extends to continuous time series `$x(t)$`:

`\begin{equation}
  x(t) =\frac{1}{2\pi} \int_{-\infty}^{\infty} X(\omega)\, e^{i\omega t} d\omega,\quad\quad X(\omega)\equiv  \int_{-\infty}^{\infty} x(t)\, e^{-i\omega t}  d t.
\end{equation}`

Note that here we are using radian frequency `$\omega$`.

--

The continuous notation is easier to understand the mechanics of *filtering* a time series, as well as spectral *blurring*.

--

But first, we need to understand the concept of convolution.

---
class: left, .toc[[✧](#toc)]
#  The Convolution Integral

The *convolution* `$h(t)$` of a function `$f(t)$` and `$g(t)$` is defined as:

`\[ h(t)\equiv  \int_{-\infty}^{\infty} f(\tau) g(t-\tau) d\tau.\]`

Note that in convolution, the order does not matter and we can show that

`\[ h(t)\equiv  \int_{-\infty}^{\infty} g(\tau) f(t-\tau) d\tau\]`

This mathematical operation is actually what is being done when “smoothing” data.
(It is like sliding the iron on the tablecloth, or pulling the tablecloth under a static iron).

---
class: left, .toc[[✧](#toc)]
# Convolution Theorem

The *convolution theorem* states convolving `$f(t)$` and `$g(t)$` in the time domain is the same as a  *multiplication* in the frequency domain.

Let `$F(\omega)$` and `$G(\omega)$` be the Fourier transforms of `$f(t)$` and `$g(t)$`, respectively. It can be shown that if

`\[h(t)= \int_{-\infty}^{\infty} f(\tau) g(t-\tau) d\tau\]`

then the fourier transform of `$h(t)$` is

`\[ H(\omega) = F(\omega) G(\omega).\]`

--
This result is key to understand what happens in the Fourier domain when you perform a time-domain smoothing.

---
class: left, .toc[[✧](#toc)]
#Smoothing

Now we consider what happens when we *smooth* the time series `$x(t)$` by the filter `$g(t)$` to obtain a smoothed version `$\widetilde x(t)$` of your time series:

`\begin{eqnarray}
\widetilde x(t)= \int_{-\infty}^{\infty} x(t-\tau) g(\tau) d\tau & \equiv & \frac{1}{2\pi} \int_{-\infty}^{\infty} \widetilde{X}(\omega) \, e^{i\omega t} d\omega.\\
&=& \frac{1}{2\pi}\int_{-\infty}^{\infty} X(\omega) G(\omega) \, e^{i\omega t} d\omega,\\
 \end{eqnarray}`
by the convolution theorem.

When we perform simple smoothing, we are also reshaping the Fourier transform of the signal by *multiplying* its Fourier transform by that of the smoothing window.

---
class: left, .toc[[✧](#toc)]
#Three Window examples

---
class: left, .toc[[✧](#toc)]
#Three Tapering Windows

---
class: left, .toc[[✧](#toc)]
#Three Tapering Windows

---
class: left, .toc[[✧](#toc)]
#Lowpass & Highpass Filters

From the convolution theorem, we understand that filtering will keep the frequencies near zero but reject higher frequencies.  For this reason they are called *low-pass filters*.

The reverse type of filtration, rejecting the low frequencies but keeping the high frequencies, is called *high-pass filtering*.

The residual `$\breve x(t)\equiv x(t) -\widetilde x(t)$` is an example of a high-pass filtered time series.

In practice, to find the frequency form of your filter, you *pad it with zeros* so that it becomes the same length as your time series, and then you take its discrete Fourier transform.

---
class: middle, center, .toc[[✧](#toc)]
#  Back to practical!

---
class: left, .toc[[✧](#toc)]
#  Convolution Theorem II

This theorem is reciprocal: is your *multiply* in the time domain, you *convolve* in the Fourier domain.

It can be shown that if

`\[ h(t) = f(t) g(t)\]`

then the fourier transform of `$h(t)$` is

`\[ H(\omega) = \int_{-\infty}^{\infty} F(\nu) G(\omega -\nu) d\omega.\]`

This result is key to understand what happens in the Fourier domain when you try to estimate spectra, i.e. *spectral bluring*, or to design band-pass filters.

---
class: left, .toc[[✧](#toc)]
# Bandpass filtering

We can use the convolution theorem to build a band-pass filter.

We want to modify the lowpass filter `$g(t)$` so that its Fourier transform is localized not about zero, but about some non-zero frequency `$\omega_o$`. To do this, we multiply `$g(t)$` by a complex exponential `$g(t) e^{i\omega_o t}$`.

It can be shown (see Oslo lectures) that the Fourier transform of `$g(t) e^{i\omega_o t}$` is `$G(\omega-\omega_o)$`, which is localized around `$\omega_o$`.

Thus, a convolution with `$g(t) e^{i\omega_o t}$` will *bandpass* the data in the vicinity of  `$\omega_o$.`

In fact, a lowpass filter is a particular type of bandpass in which the center of the *pass band* has been chosen as zero frequency.

---
class: middle, center, .toc[[✧](#toc)]
#  Back to practical!

---
class: left, .toc[[✧](#toc)]
#Effect of Truncation

Now imagine instead that we have a *continuously* sampled time series of length `$T$`, that is, we have `$z(t)$` but only between times `$-T/2$` and `$T/2$`. This is like multiplying `$z(t)$` by a function `$g(t)$` which is equal to one between `$-T/2$` and `$T/2$` and 0 otherwise:

`\[ z_T(t) = g(t) \times z(t) \]`

We will denote this truncted version of `$z(t)$` by `$z_T(t)$`.

How does the spectrum compare of `$z_T(t)$` compare with that of  `$z(t)$`?

--

Q.  Using one of the windows encountered today, how can we express the relationship between `$z(t)$` and `$z_T(t)$`?

--

Q.  Therefore, using another theorem learned today, what is the difference between their spectra?
---
class: left, .toc[[✧](#toc)]
#Spectral Blurring

The spectrum of the truncated time series is *blurred* through smoothing with a function `$F_{T}(\omega)$` that is the *square* of the Fourier transform of a boxcar:

`\[\widetilde S(\omega) \equiv\frac{1}{2\pi}\int_{-\infty}^\infty S(\nu) \,F_{T}(\nu-\omega)\, d \nu.\]`

The smoothing function, which is known as the *Fejér kernel*
`\[F_T(\omega)\equiv \int_{-T}^{T}\left(1-\frac{|\tau|}{T}\right) \, e^{i\omega\tau} \, d \tau
=\frac{1}{T}\frac{\sin^2(\omega T/2)}{(\omega/2)^2}\]`
is essentially a squared version of the “sinc” or `$\sin(x)/x$` function.

However, `$\sin(x)/x$` is not a very smooth function at all!

---
class: left, .toc[[✧](#toc)]
#Multitapering Revisited

We can now understand the purpose of multitapering.

*Doing nothing* in your spectral estimate is equivalent to *truncating* your data, thus implicitly *smoothing* the true spectrum by an extremely undesirable function!

The Fejér kernel has a major problem in that it is not *well concentrated*.  Its “side lobes” are large, leading to a kind of error called *broadband bias*.

This is the source of the error shown in the motivating example.

Next we take a look at three different tapering functions and their squared Fourier transforms.  The broadband bias is most clear if we use logarithmic scaling for the `$y$`-axis.

---
class: left, .toc[[✧](#toc)]
#Three Tapering Windows

---
class: left, .toc[[✧](#toc)]
#Three Tapering Windows

---
class: left, .toc[[✧](#toc)]
#Three Tapering Windows

 </textarea>


text:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<type language="gradle" name="org.gradle.nativeplatform.test.cunit.plugins.CUnitConventionPlugin.Rules" version="3.0" superType="org.gradle.model.RuleSource">
    <method name="createCUnitTestSuitePerComponent" returnType="void">
        <parameter type="org.gradle.testing.base.TestSuiteContainer" name="testSuites"/>
        <parameter type="org.gradle.model.ModelMap" name="components"/>
    </method>
</type>


text:
using System.Text;
using System;
using System.Diagnostics.Contracts;

namespace System.Text
{
    // An Encoder is used to encode a sequence of blocks of characters into
    // a sequence of blocks of bytes. Following instantiation of an encoder,
    // sequential blocks of characters are converted into blocks of bytes through
    // calls to the GetBytes method. The encoder maintains state between the
    // conversions, allowing it to correctly encode character sequences that span
    // adjacent blocks.
    //
    // Instances of specific implementations of the Encoder abstract base
    // class are typically obtained through calls to the GetEncoder method
    // of Encoding objects.
    //

    internal class EncoderNLS : Encoder
    {
        // Need a place for the last left over character, most of our encodings use this
        internal char charLeftOver;

        protected EncodingNLS m_encoding;

        protected bool m_mustFlush;
        internal bool m_throwOnOverflow;
        internal int m_charsUsed;
        internal EncoderFallback m_fallback;
        internal EncoderFallbackBuffer m_fallbackBuffer;

        internal EncoderNLS(EncodingNLS encoding)
        {
            m_encoding = encoding;
            m_fallback = m_encoding.EncoderFallback;
            Reset();
        }

        internal new EncoderFallback Fallback
        {
            get { return m_fallback; }
        }

        internal bool InternalHasFallbackBuffer
        {
            get
            {
                return m_fallbackBuffer != null;
            }
        }

        public new EncoderFallbackBuffer FallbackBuffer
        {
            get
            {
                if (m_fallbackBuffer == null)
                {
                    if (m_fallback != null)
                        m_fallbackBuffer = m_fallback.CreateFallbackBuffer();
                    else
                        m_fallbackBuffer = EncoderFallback.ReplacementFallback.CreateFallbackBuffer();
                }

                return m_fallbackBuffer;
            }
        }

        // This one is used when deserializing (like UTF7Encoding.Encoder)
        internal EncoderNLS()
        {
            m_encoding = null;
            Reset();
        }

        public override void Reset()
        {
            charLeftOver = (char)0;
            if (m_fallbackBuffer != null)
                m_fallbackBuffer.Reset();
        }

        [System.Security.SecuritySafeCritical]  // auto-generated
        public override unsafe int GetByteCount(char[] chars, int index, int count, bool flush)
        {
            // Validate input parameters
            if (chars == null)
                throw new ArgumentNullException("chars", SR.ArgumentNull_Array);

            if (index < 0 || count < 0)
                throw new ArgumentOutOfRangeException((index < 0 ? "index" : "count"), SR.ArgumentOutOfRange_NeedNonNegNum);

            if (chars.Length - index < count)
                throw new ArgumentOutOfRangeException("chars", SR.ArgumentOutOfRange_IndexCountBuffer);
            Contract.EndContractBlock();

            // Avoid empty input problem
            if (chars.Length == 0)
                chars = new char[1];

            // Just call the pointer version
            int result = -1;
            fixed (char* pChars = chars)
            {
                result = GetByteCount(pChars + index, count, flush);
            }
            return result;
        }

        [System.Security.SecurityCritical]  // auto-generated
        public unsafe int GetByteCount(char* chars, int count, bool flush)
        {
            // Validate input parameters
            if (chars == null)
                throw new ArgumentNullException("chars", SR.ArgumentNull_Array);

            if (count < 0)
                throw new ArgumentOutOfRangeException("count", SR.ArgumentOutOfRange_NeedNonNegNum);
            Contract.EndContractBlock();

            m_mustFlush = flush;
            m_throwOnOverflow = true;
            return m_encoding.GetByteCount(chars, count, this);
        }

        [System.Security.SecuritySafeCritical]  // auto-generated
        public override unsafe int GetBytes(char[] chars, int charIndex, int charCount,
                                              byte[] bytes, int byteIndex, bool flush)
        {
            // Validate parameters
            if (chars == null || bytes == null)
                throw new ArgumentNullException((chars == null ? "chars" : "bytes"), SR.ArgumentNull_Array);

            if (charIndex < 0 || charCount < 0)
                throw new ArgumentOutOfRangeException((charIndex < 0 ? "charIndex" : "charCount"), SR.ArgumentOutOfRange_NeedNonNegNum);

            if (chars.Length - charIndex < charCount)
                throw new ArgumentOutOfRangeException("chars", SR.ArgumentOutOfRange_IndexCountBuffer);

            if (byteIndex < 0 || byteIndex > bytes.Length)
                throw new ArgumentOutOfRangeException("byteIndex", SR.ArgumentOutOfRange_Index);
            Contract.EndContractBlock();

            if (chars.Length == 0)
                chars = new char[1];

            int byteCount = bytes.Length - byteIndex;
            if (bytes.Length == 0)
                bytes = new byte[1];

            // Just call pointer version
            fixed (char* pChars = chars)
                fixed (byte* pBytes = bytes)

                    // Remember that charCount is # to decode, not size of array.
                    return GetBytes(pChars + charIndex, charCount,
                                    pBytes + byteIndex, byteCount, flush);
        }

        [System.Security.SecurityCritical]  // auto-generated
        public unsafe int GetBytes(char* chars, int charCount, byte* bytes, int byteCount, bool flush)
        {
            // Validate parameters
            if (chars == null || bytes == null)
                throw new ArgumentNullException((chars == null ? "chars" : "bytes"), SR.ArgumentNull_Array);

            if (byteCount < 0 || charCount < 0)
                throw new ArgumentOutOfRangeException((byteCount < 0 ? "byteCount" : "charCount"), SR.ArgumentOutOfRange_NeedNonNegNum);
            Contract.EndContractBlock();

            m_mustFlush = flush;
            m_throwOnOverflow = true;
            return m_encoding.GetBytes(chars, charCount, bytes, byteCount, this);
        }

        // This method is used when your output buffer might not be large enough for the entire result.
        // Just call the pointer version.  (This gets bytes)
        [System.Security.SecuritySafeCritical]  // auto-generated
        public override unsafe void Convert(char[] chars, int charIndex, int charCount,
                                              byte[] bytes, int byteIndex, int byteCount, bool flush,
                                              out int charsUsed, out int bytesUsed, out bool completed)
        {
            // Validate parameters
            if (chars == null || bytes == null)
                throw new ArgumentNullException((chars == null ? "chars" : "bytes"), SR.ArgumentNull_Array);

            if (charIndex < 0 || charCount < 0)
                throw new ArgumentOutOfRangeException((charIndex < 0 ? "charIndex" : "charCount"), SR.ArgumentOutOfRange_NeedNonNegNum);

            if (byteIndex < 0 || byteCount < 0)
                throw new ArgumentOutOfRangeException((byteIndex < 0 ? "byteIndex" : "byteCount"), SR.ArgumentOutOfRange_NeedNonNegNum);

            if (chars.Length - charIndex < charCount)
                throw new ArgumentOutOfRangeException("chars", SR.ArgumentOutOfRange_IndexCountBuffer);

            if (bytes.Length - byteIndex < byteCount)
                throw new ArgumentOutOfRangeException("bytes", SR.ArgumentOutOfRange_IndexCountBuffer);

            Contract.EndContractBlock();

            // Avoid empty input problem
            if (chars.Length == 0)
                chars = new char[1];
            if (bytes.Length == 0)
                bytes = new byte[1];

            // Just call the pointer version (can't do this for non-msft encoders)
            fixed (char* pChars = chars)
            {
                fixed (byte* pBytes = bytes)
                {
                    Convert(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, flush,
                        out charsUsed, out bytesUsed, out completed);
                }
            }
        }

        // This is the version that uses pointers.  We call the base encoding worker function
        // after setting our appropriate internal variables.  This is getting bytes
        [System.Security.SecurityCritical]  // auto-generated
        public unsafe void Convert(char* chars, int charCount,
                                              byte* bytes, int byteCount, bool flush,
                                              out int charsUsed, out int bytesUsed, out bool completed)
        {
            // Validate input parameters
            if (bytes == null || chars == null)
                throw new ArgumentNullException(bytes == null ? "bytes" : "chars", SR.ArgumentNull_Array);

            if (charCount < 0 || byteCount < 0)
                throw new ArgumentOutOfRangeException((charCount < 0 ? "charCount" : "byteCount"), SR.ArgumentOutOfRange_NeedNonNegNum);
            Contract.EndContractBlock();

            // We don't want to throw
            m_mustFlush = flush;
            m_throwOnOverflow = false;
            m_charsUsed = 0;

            // Do conversion
            bytesUsed = m_encoding.GetBytes(chars, charCount, bytes, byteCount, this);
            charsUsed = m_charsUsed;

            // Its completed if they've used what they wanted AND if they didn't want flush or if we are flushed
            completed = (charsUsed == charCount) && (!flush || !HasState) &&
                (m_fallbackBuffer == null || m_fallbackBuffer.Remaining == 0);
            // Our data thingies are now full, we can return
        }

        public Encoding Encoding
        {
            get
            {
                return m_encoding;
            }
        }

        public bool MustFlush
        {
            get
            {
                return m_mustFlush;
            }
        }

        // Anything left in our encoder?
        internal virtual bool HasState
        {
            get
            {
                return (charLeftOver != (char)0);
            }
        }

        // Allow encoding to clear our must flush instead of throwing (in ThrowBytesOverflow)
        internal void ClearMustFlush()
        {
            m_mustFlush = false;
        }
    }
}


text:
	/* ${structure_member_description}
	 */
	${structure_member_data_type} ${structure_member_name};


text:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.9.0"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>EmbASP-Python v7.1.0: Member List</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>

<link href="search/search.css" rel="stylesheet" type="text/css"/>

<link href="doxygen.css" rel="stylesheet" type="text/css" />

EmbASP-Python v7.1.0

parsers

asp

asp_parser_base

ASPGrammarParser

ASPGrammarParser

TermContext

parsers.asp.asp_parser_base.ASPGrammarParser.ASPGrammarParser.TermContext Member List

This is the complete list of members for parsers.asp.asp_parser_base.ASPGrammarParser.ASPGrammarParser.TermContext, including all inherited members.

__init__(self, parser, parent=None, invokingState=-1)	parsers.asp.asp_parser_base.ASPGrammarParser.ASPGrammarParser.TermContext

accept(self, visitor)	parsers.asp.asp_parser_base.ASPGrammarParser.ASPGrammarParser.TermContext

getRuleIndex(self)	parsers.asp.asp_parser_base.ASPGrammarParser.ASPGrammarParser.TermContext

IDENTIFIER(self)	parsers.asp.asp_parser_base.ASPGrammarParser.ASPGrammarParser.TermContext

INTEGER(self)	parsers.asp.asp_parser_base.ASPGrammarParser.ASPGrammarParser.TermContext

parser	parsers.asp.asp_parser_base.ASPGrammarParser.ASPGrammarParser.TermContext

predicate_atom(self)	parsers.asp.asp_parser_base.ASPGrammarParser.ASPGrammarParser.TermContext

STRING(self)	parsers.asp.asp_parser_base.ASPGrammarParser.ASPGrammarParser.TermContext

term(self, i=None)	parsers.asp.asp_parser_base.ASPGrammarParser.ASPGrammarParser.TermContext

<address class="footer">
Generated by  1.9.0
</address>


text:
import { expect } from 'chai';
import { spec } from 'modules/widespaceBidAdapter';
import includes from 'core-js/library/fn/array/includes';

describe('+widespaceAdatperTest', () => {
  // Dummy bid request
  const bidRequest = [{
    'adUnitCode': 'div-gpt-ad-1460505748561-0',
    'auctionId': 'bf1e57ee-fff2-4304-8143-91aaf423a948',
    'bidId': '4045696e2278cd',
    'bidder': 'widespace',
    'params': {
      sid: '7b6589bf-95c8-4656-90b9-af9737bb9ad3',
      currency: 'EUR',
      demo: {
        gender: 'M',
        country: 'Sweden',
        region: 'Stockholm',
        postal: '15115',
        city: 'Stockholm',
        yob: '1984'
      }
    },
    'bidderRequestId': '37a5f053efef34',
    'sizes': [[320, 320], [300, 250], [300, 300]],
    'transactionId': '4f68b713-04ba-4d7f-8df9-643bcdab5efb'
  }, {
    'adUnitCode': 'div-gpt-ad-1460505748561-1',
    'auctionId': 'bf1e57ee-fff2-4304-8143-91aaf423a944',
    'bidId': '4045696e2278ab',
    'bidder': 'widespace',
    'params': {
      sid: '7b6589bf-95c8-4656-90b9-af9737bb9ad4',
      demo: {
        gender: 'M',
        country: 'Sweden',
        region: 'Stockholm',
        postal: '15115',
        city: 'Stockholm',
        yob: '1984'
      }
    },
    'bidderRequestId': '37a5f053efef34',
    'sizes': [[300, 300]],
    'transactionId': '4f68b713-04ba-4d7f-8df9-643bcdab5efv'
  }];

  // Dummy bid response with ad code
  const bidResponse = {
    body: [{
      'adId': '12345',
      'bidId': '67890',
      'code': '

',
      'cpm': 6.6,
      'currency': 'EUR',
      'height': 300,
      'netRev': true,
      'reqId': '224804081406',
      'status': 'ad',
      'ttl': 30,
      'width': 300,
      'syncPixels': ['https://url1.com/url', 'https://url2.com/url']
    }],
    headers: {}
  };

  // Dummy bid response of noad
  const bidResponseNoAd = {
    body: [{
      'status': 'noad',
    }],
    headers: {}
  };

  // Appending a div with id of adUnitCode so we can calculate vol
  const div1 = document.createElement('div');
  div1.id = bidRequest[0].adUnitCode;
  document.body.appendChild(div1);
  const div2 = document.createElement('div');
  div2.id = bidRequest[0].adUnitCode;
  document.body.appendChild(div2);

  // Adding custom data cookie se we can test cookie is readable
  const theDate = new Date();
  const expDate = new Date(theDate.setMonth(theDate.getMonth() + 1)).toGMTString();
  window.document.cookie = `wsCustomData1={id: test};path=/;expires=${expDate};`;
  const PERF_DATA = JSON.stringify({perf_status: 'OK', perf_reqid: '226920425154', perf_ms: '747'});
  window.document.cookie = `wsPerfData123=${PERF_DATA};path=/;expires=${expDate};`;

  // Connect dummy data test
  const CONNECTION = navigator.connection || navigator.webkitConnection;
  if (CONNECTION && CONNECTION.type && CONNECTION.downlinkMax) {
    navigator.connection.downlinkMax = 80;
    navigator.connection.type = 'wifi';
  }

  describe('+bidRequestValidity', () => {
    it('bidRequest with sid and currency params', () => {
      expect(spec.isBidRequestValid({
        bidder: 'widespace',
        params: {
          sid: '7b6589bf-95c8-4656-90b9-af9737bb9ad3',
          currency: 'EUR'
        }
      })).to.equal(true);
    });

    it('-bidRequest with missing sid', () => {
      expect(spec.isBidRequestValid({
        bidder: 'widespace',
        params: {
          currency: 'EUR'
        }
      })).to.equal(false);
    });

    it('-bidRequest with missing currency', () => {
      expect(spec.isBidRequestValid({
        bidder: 'widespace',
        params: {
          sid: '7b6589bf-95c8-4656-90b9-af9737bb9ad3'
        }
      })).to.equal(true);
    });
  });

  describe('+bidRequest', () => {
    const request = spec.buildRequests(bidRequest);
    const UrlRegExp = /^((ftp|http|https):)?\/\/[^ "]+$/;

    it('-bidRequest method is POST', () => {
      expect(request[0].method).to.equal('POST');
    });

    it('-bidRequest url is valid', () => {
      expect(UrlRegExp.test(request[0].url)).to.equal(true);
    });

    it('-bidRequest data exist', () => {
      expect(request[0].data).to.exists;
    });

    it('-bidRequest data is form data', () => {
      expect(typeof request[0].data).to.equal('string');
    });

    it('-bidRequest options have header type', () => {
      expect(request[0].options.contentType).to.exists;
    });

    it('-cookie test for wsCustomData ', () => {
      expect(request[0].data.indexOf('hb.cd') > -1).to.equal(true);
    });
  });

  describe('+interpretResponse', () => {
    it('-required params available in response', () => {
      const result = spec.interpretResponse(bidResponse, bidRequest);
      let requiredKeys = [
        'requestId',
        'cpm',
        'width',
        'height',
        'creativeId',
        'currency',
        'netRevenue',
        'ttl',
        'referrer',
        'ad'
      ];
      const resultKeys = Object.keys(result[0]);
      requiredKeys.forEach((key) => {
        expect(includes(resultKeys, key)).to.equal(true);
      });

      // Each value except referrer should not be empty|null|undefined
      result.forEach((res) => {
        Object.keys(res).forEach((resKey) => {
          if (resKey !== 'referrer') {
            expect(res[resKey]).to.not.be.null;
            expect(res[resKey]).to.not.be.undefined;
            expect(res[resKey]).to.not.equal('');
          }
        });
      });
    });

    it('-empty result if noad responded', () => {
      const noAdResult = spec.interpretResponse(bidResponseNoAd, bidRequest);
      expect(noAdResult.length).to.equal(0);
    });

    it('-empty response should not breake anything in adapter', () => {
      const noResponse = spec.interpretResponse({}, bidRequest);
      expect(noResponse.length).to.equal(0);
    });
  });

  describe('+getUserSyncs', () => {
    it('-always return an array', () => {
      const userSync_test1 = spec.getUserSyncs({}, [bidResponse]);
      expect(Array.isArray(userSync_test1)).to.equal(true);

      const userSync_test2 = spec.getUserSyncs({}, [bidResponseNoAd]);
      expect(Array.isArray(userSync_test2)).to.equal(true);

      const userSync_test3 = spec.getUserSyncs({}, [bidResponse, bidResponseNoAd]);
      expect(Array.isArray(userSync_test3)).to.equal(true);

      const userSync_test4 = spec.getUserSyncs();
      expect(Array.isArray(userSync_test4)).to.equal(true);

      const userSync_test5 = spec.getUserSyncs({}, []);
      expect(Array.isArray(userSync_test5)).to.equal(true);
    });
  });
});