__all__ = ["TileLayoutWdg"]

import re
from pyasm.common import Common
from pyasm.search import Search, SearchKey
from pyasm.web import DivWdg, Table, SpanWdg
from pyasm.widget import ThumbWdg, IconWdg, TextWdg, HiddenWdg
from tactic.ui.common import BaseRefreshWdg
from tactic.ui.container import SmartMenu

from table_layout_wdg import FastTableLayoutWdg
from tactic.ui.widget import IconButtonWdg, SingleButtonWdg, ActionButtonWdg

from tool_layout_wdg import ToolLayoutWdg

class TileLayoutWdg(ToolLayoutWdg):

    ARGS_KEYS = ToolLayoutWdg.ARGS_KEYS.copy()
    ARGS_KEYS['top_view'] = {
            'description': 'an optional custom layout for the title area of the tile',
            'order' : '01',
            'category': 'Display'
        }

    ARGS_KEYS['bottom_view'] = {
            'description': 'an optional custom layout for the bottom area of the tile',
            'order' : '02',
            'category': 'Display'
        }

    ARGS_KEYS['show_scale'] = {
            'description': 'If set to true, the scale slider bar is displayed',
            'type': 'SelectWdg',
            'values': 'true|false',
            'order' : '03',
            'category': 'Display'
    }
    ARGS_KEYS['scale'] = {
            'description': 'Initial Scale. If not set, it defaults to 100',
            'type': 'TextWdg',
            'order' : '04',
            'category': 'Display'

    }
    ARGS_KEYS['sticky_scale'] = {
            'description': 'If set to local, the scale is sticky in the current view until page refresh',
            'type': 'SelectWdg',
            'values': 'local|global',
            'order' : '05',
            'category': 'Display'

    }
    ARGS_KEYS['styles'] = {
            'description': 'styles in a string that can be applied to the top container of this Tile Layout',
            'type': 'TextWdg',
            'order' : '06',
            'category': 'Display'

    }
    ARGS_KEYS['aspect_ratio'] = {
            'description': 'Custom aspect ratio like 240,110 for the tiles',
            'type': 'TextWdg',
            'order' : '07',
            'category': 'Display'

    }
    ARGS_KEYS['spacing'] = {
            'description': 'Custom tile spacing between tiles',
            'type': 'TextWdg',
            'order' : '08',
            'category': 'Display'

    }

    def can_select(my):
        return True

    def can_expand(my):
        return True

    def get_expand_behavior(my):
        return {
            'type': 'click_up',
            'cbjs_action': '''
            var layout = spt.tile_layout.set_layout(bvr.src_el);

            // get the current scale
            var scale = spt.tile_layout.get_scale();
            if (scale) scale = parseInt(scale);

            if (scale == 100) {
                scale = layout.getAttribute("last_scale");
                if (scale) scale = parseInt(scale)
                else scale = 100
            }
            else {
                layout.setAttribute("last_scale", scale);
                scale = 100;
            }

            spt.tile_layout.set_scale(scale);
            '''

        }

    def get_content_wdg(my):
        div = DivWdg()
        div.add_class("spt_tile_layout_top")
        if my.top_styles:
            div.add_styles(my.top_styles)
        inner = DivWdg()
        div.add(inner)

        menus_in = {}
        # set up the context menus
        if my.show_context_menu == True:
            menus_in['DG_HEADER_CTX'] = [ my.get_smart_header_context_menu_data() ]
            menus_in['DG_DROW_SMENU_CTX'] = [ my.get_data_row_smart_context_menu_details() ]
        elif my.show_context_menu == 'none':
            div.add_event('oncontextmenu', 'return false;')
        if menus_in:
            SmartMenu.attach_smart_context_menu( inner, menus_in, False )

        temp = my.kwargs.get("temp")
        has_loading = False

        inner.add_style("margin-left: 20px")

        inner.add_attr("ondragenter", "return false")
        inner.add_attr("ondragover", "return false")
        inner.add_attr("ondrop", "spt.thumb.background_drop(event, this)")

        inner.add("
")

        if my.sobjects:
            inner.add( my.get_scale_wdg() )

            for row, sobject in enumerate(my.sobjects):

                if False and not temp and row > 4:
                    tile_wdg = DivWdg()
                    inner.add(tile_wdg)
                    tile_wdg.add_style("width: 120px")
                    tile_wdg.add_style("height: 120px")
                    tile_wdg.add_style("float: left")
                    tile_wdg.add_style("padding: 20px")
                    tile_wdg.add_style("text-align: center")
                    tile_wdg.add('')
                    tile_wdg.add(" Loading ...")
                    tile_wdg.add_attr("spt_search_key", sobject.get_search_key())
                    tile_wdg.add_class("spt_loading")
                    has_loading = True
                    continue

                kwargs = my.kwargs.copy()
                tile = my.get_tile_wdg(sobject)
                inner.add(tile)
        else:
            table = Table()
            inner.add(table)
            my.handle_no_results(table)

        chunk_size = 5
        if has_loading:
            inner.add_behavior( {
            'type': 'load',
            'chunk': chunk_size,
            'cbjs_action': '''
            var layout = bvr.src_el.getParent(".spt_layout");
            spt.table.set_layout(layout);
            var rows = layout.getElements(".spt_loading");

            var jobs = [];
            var count = 0;
            var chunk = bvr.chunk;
            while (true) {
                var job_item = rows.slice(count, count+chunk);
                if (job_item.length == 0) {
                    break;
                }
                jobs.push(job_item);
                count += chunk;
            }

            var count = -1;
            var func = function() {
                count += 1;
                var rows = jobs[count];
                if (! rows || rows.length == 0) {
                    return;
                }
                for (var i = 0; i < rows.length; i++) {
                    rows[i].removeClass("spt_loading");
                }
                spt.table.refresh_rows(rows, null, null, {on_complete: func});
            }
            func();

            '''
            } )

        inner.add("
")
        return div

    def init(my):
        my.scale_called = False
        my.scale = None
        top_view = my.kwargs.get("top_view")
        if top_view:
            kwargs = {
                'view': top_view,
            }
            from tactic.ui.panel import CustomLayoutWdg
            my.title_wdg = CustomLayoutWdg(**kwargs)
        else:
            my.title_wdg = None
        my.sticky_scale = my.kwargs.get('sticky_scale')
        if my.sticky_scale == 'local':
            # NOTE: each side bar link has a unique name on each level, but it's not always available
            # not in page refresh or built-in links
            # element = my.kwargs.get('element_name')
            my.scale_prefix = '%s:%s' %(my.search_type, my.view)
        else:
            my.scale_prefix = ''

        bottom_view = my.kwargs.get("bottom_view")
        if bottom_view:
            kwargs = {
                'view': bottom_view,
                'load': 'sequence',
            }
            from tactic.ui.panel import CustomLayoutWdg
            my.bottom = CustomLayoutWdg(**kwargs)
        else:
            my.bottom = None

        from tactic.ui.filter import FilterData
        filter_data = FilterData.get()
        data_list = filter_data.get_values_by_prefix("tile_layout")
        if data_list:
            data = data_list[0]
        else:
            data = {}

        my.scale = data.get("scale")
        if my.scale == None:
            my.scale = my.kwargs.get("scale")
        if my.scale == None:
            my.scale = 100

        my.aspect_ratio = my.kwargs.get('aspect_ratio')
        if my.aspect_ratio:
            parts = re.split('[\Wx]+', my.aspect_ratio)
            my.aspect_ratio = (int(parts[0]), int(parts[1]))
        else:
            my.aspect_ratio = (240, 160)

        my.top_styles = my.kwargs.get('styles')
        my.spacing = my.kwargs.get('spacing')
        if not my.spacing:
            my.spacing = '10'

        super(TileLayoutWdg, my).init()

    def add_layout_behaviors(my, layout_wdg):

        layout_wdg.add_relay_behavior( {
            'type': 'mouseup',
            'bvr_match_class': 'spt_tile_detail',
            'cbjs_action': '''
            spt.tab.set_main_body_tab();
            var top = bvr.src_el.getParent(".spt_tile_top");
            var search_key = top.getAttribute("spt_search_key");
            var name = top.getAttribute("spt_name");
            var search_code = top.getAttribute("spt_search_code");
            var class_name = 'tactic.ui.tools.SObjectDetailWdg';
            //var class_name = 'tactic.ui.tools.RepoBrowserContentWdg';
            var kwargs = {
                search_key: search_key
            };
            spt.tab.add_new(search_code, name, class_name, kwargs);
            '''
        } )

        mode = my.kwargs.get("expand_mode")
        if not mode:
            mode = "gallery"

        gallery_width = my.kwargs.get("gallery_width")
        if not gallery_width:
            gallery_width = ''
        if mode == "view":
            layout_wdg.add_relay_behavior( {
                'type': 'click',
                'bvr_match_class': 'spt_tile_content',
                'cbjs_action': '''
                var top = bvr.src_el.getParent(".spt_tile_top");
                var search_key = top.getAttribute("spt_search_key");
                var server = TacticServerStub.get();
                var snapshot = server.get_snapshot(search_key, {context: "", process:"publish",include_web_paths_dict:true});
                if (snapshot.__search_key__) {
                    window.open(snapshot.__web_paths_dict__.main);
                }
                else {
                    var snapshot = server.get_snapshot(search_key, {context: "",include_web_paths_dict:true});
                    if (snapshot.__search_key__) {
                        window.open(snapshot.__web_paths_dict__.main);
                    }
                    else {
                        alert("WARNING: No file for this asset");
                    }
                }
                '''
            } )
        elif mode == "gallery":
            gallery_div = DivWdg()
            layout_wdg.add( gallery_div )
            gallery_div.add_class("spt_tile_gallery")

            layout_wdg.add_relay_behavior( {
                'type': 'click',
                'width': gallery_width,
                'bvr_match_class': 'spt_tile_content',
                'cbjs_action': '''
                var layout = bvr.src_el.getParent(".spt_layout");
                var tile_tops = layout.getElements(".spt_tile_top");

                var search_keys = [];
                for (var i = 0; i < tile_tops.length; i++) {
                    var tile_top = tile_tops[i];
                    var search_key = tile_top.getAttribute("spt_search_key");
                    search_keys.push(search_key);
                }

                var tile_top = bvr.src_el.getParent(".spt_tile_top");
                var search_key = tile_top.getAttribute("spt_search_key");

                var class_name = 'tactic.ui.widget.gallery_wdg.GalleryWdg';
                var kwargs = {
                    search_keys: search_keys,
                    search_key: search_key,
                };
                if (bvr.width)
                    kwargs['width'] = bvr.width;
                var gallery_el = layout.getElement(".spt_tile_gallery");
                spt.panel.load(gallery_el, class_name, kwargs);

                '''
            } )

        bg1 = layout_wdg.get_color("background3")
        bg2 = layout_wdg.get_color("background3", 5)
        layout_wdg.add_relay_behavior( {
            'type': 'mouseover',
            'bvr_match_class': 'spt_tile_top',
            'cbjs_action': '''
            bvr.src_el.setStyle("opacity", "0.8");
            var el = bvr.src_el.getElement(".spt_tile_title");
            if (el)
                el.setStyle("background", "%s");
            ''' % bg2
        } )

        layout_wdg.add_relay_behavior( {
            'type': 'mouseout',
            'bvr_match_class': 'spt_tile_top',
            'cbjs_action': '''
            bvr.src_el.setStyle("opacity", "1.0");
            var el = bvr.src_el.getElement(".spt_tile_title");
            if (el)
                el.setStyle("background", "%s");
            ''' % bg1
        } )

        layout_wdg.add_behavior( {
            'type': 'load',
            'cbjs_action': '''

            spt.thumb = {};

            spt.thumb.background_drop = function(evt, el) {
                evt.stopPropagation();
                evt.preventDefault();

                var top = $(el);
                top.setStyle("background", "#0F0");
            }

            spt.thumb.noop = function(evt, el) {
                evt.stopPropagation();
                evt.preventDefault();
                evt.dataTransfer.dropEffect = 'copy';
                var files = evt.dataTransfer.files;

                var top = $(el);
                var thumb_el = top.getElement(".spt_thumb_top");

                for (var i = 0; i < files.length; i++) {
                    var size = files[i].size;
                    var file = files[i];

                    setTimeout( function() {
                        var loadingImage = loadImage(
                            file,
                            function (img) {
                                thumb_el.innerHTML = "";
                                thumb_el.appendChild(img);
                            },
                            {maxWidth: 240, canvas: true, contain: true}
                        );
                    }, 0 );

                    var search_key = top.getAttribute("spt_search_key");
                    var filename = file.name;
                    var context = "publish" + "/" + filename;

                    var upload_file_kwargs =  {
                        files: files,
                        upload_complete: function() {
                            var server = TacticServerStub.get();
                            var kwargs = {mode: 'uploaded'};
                            server.simple_checkin( search_key, context, filename, kwargs);
                        }
                    };
                    spt.html5upload.upload_file(upload_file_kwargs);

                }
            }
            '''
        } )

        border = layout_wdg.get_color("border")

        layout_wdg.add_relay_behavior( {
            'type': 'mouseup',
            'border': border,
            'bvr_match_class': 'spt_tile_select',
            'cbjs_action': '''
            if (evt.shift == true) {

                spt.table.set_table(bvr.src_el);
                var row = bvr.src_el.getParent(".spt_table_row");

                var rows = spt.table.get_all_rows(true);
                var last_selected = spt.table.last_selected_row;
                var last_index = -1;
                var cur_index = -1;
                for (var i = 0; i < rows.length; i++) {
                    if (rows[i] == last_selected) {
                        last_index = i;
                    }
                    if (rows[i] == row) {
                        cur_index = i;
                    }

                    if (cur_index != -1 && last_index != -1) {
                        break;
                    }

                }
                var start_index;
                var end_index;
                if (last_index < cur_index) {
                    start_index = last_index;
                    end_index = cur_index;
                }
                else {
                    start_index = cur_index;
                    end_index = last_index;
                }

                var select = last_selected.hasClass("spt_table_selected");
                for (var i = start_index; i < end_index+1; i++) {

                    var row = rows[i];
                    var checkbox = row.getElement(".spt_tile_checkbox");

                    if (!select) {
                        checkbox.checked = false;
                        row.removeClass("spt_table_selected");

                        row.setStyle("border", "solid 1px " + bvr.border);
                        var size = row.getSize();
                        row.setStyle("width", size.x+6);
                        row.setStyle("height", size.y+6);

                    }
                    else {
                        checkbox.checked = true;
                        //row.addClass("spt_table_selected");
                        var size = row.getSize();
                        row.setStyle("width", size.x-10);
                        row.setStyle("height", size.y-10);
                        row.setStyle("border", "solid 5px yellow");
                        spt.table.select_row(row);

                    }
                }

            }
            else {

                var row = bvr.src_el.getParent(".spt_table_row");
                var checkbox = bvr.src_el.getElement(".spt_tile_checkbox");

                if (checkbox.checked == true) {
                    checkbox.checked = false;
                    row.removeClass("spt_table_selected");

                    row.setStyle("border", "solid 1px " + bvr.border);

                    var size = row.getSize();
                    row.setStyle("width", size.x+6);
                    row.setStyle("height", size.y+6);

                }
                else {
                    checkbox.checked = true;
                    //row.addClass("spt_table_selected");

                    var size = row.getSize();
                    row.setStyle("width", size.x-10);
                    row.setStyle("height", size.y-10);
                    row.setStyle("border", "solid 5px yellow");
                    spt.table.select_row(row);

                }

            }

            '''
        } )

    def get_tile_wdg(my, sobject):

        div = DivWdg()
        div.add_class("spt_tile_top")
        div.add_style('margin', my.spacing)
        div.add_style('background-color','transparent')

        div.add_class("spt_table_row")
        div.add_class("spt_table_row_%s" % my.table_id)

        if my.kwargs.get("show_title") not in ['false', False]:
            if my.title_wdg:
                my.title_wdg.set_sobject(sobject)
                div.add(my.title_wdg.get_buffer_display())
            else:
                title_wdg = my.get_title(sobject)
                div.add( title_wdg )

        div.add_attr("spt_search_key", sobject.get_search_key())
        div.add_attr("spt_name", sobject.get_name())
        div.add_attr("spt_search_code", sobject.get_code())

        SmartMenu.assign_as_local_activator( div, 'DG_DROW_SMENU_CTX' )

        if my.kwargs.get("show_drop_shadow") not in ['false', False]:
            div.set_box_shadow()
        div.add_color("background", "background", -3)

        div.add_style("overflow: hidden")

        div.add_style("float: left")

        thumb_div = DivWdg()
        #thumb_div.add_styles('margin-left: auto; margin-right: auto')
        thumb_div.add_class("spt_tile_content")
        #thumb_div.add_class("spt_tile_detail")
        div.add(thumb_div)

        thumb_div.add_style("width: %s" % my.aspect_ratio[0])

        thumb_div.add_style("height: %s" % my.aspect_ratio[1])
        #thumb_div.add_style("overflow: hidden")

        thumb = ThumbWdg2()
        thumb.set_sobject(sobject)
        thumb_div.add(thumb)
        thumb_div.add_border()

        #bottom_view = my.kwargs.get("bottom_view")
        #if bottom_view:
        #    div.add( my.get_view_wdg(sobject, bottom_view) )
        if my.bottom:
            my.bottom.set_sobject(sobject)
            div.add(my.bottom.get_buffer_display())

        div.add_attr("ondragenter", "return false")
        div.add_attr("ondragover", "return false")
        div.add_attr("ondrop", "spt.thumb.noop(event, this)")

        return div

    def get_view_wdg(my, sobject, view):
        div = DivWdg()
        #div.add_style("overflow: hidden")

        kwargs = {
            'view': view,
        }
        from tactic.ui.panel import CustomLayoutWdg
        layout = CustomLayoutWdg(**kwargs)
        layout.set_sobject(sobject)
        div.add(layout.get_buffer_display())
        return div

    def get_shelf_wdg(my):
        return my.get_scale_wdg()

    def get_scale_wdg(my):

        if my.scale_called == True:
            return None
        my.scale_called = True

        show_scale = my.kwargs.get("show_scale")

        div = DivWdg()
        if show_scale in [False, 'false']:
            div.add_style("display: none")
        div.add_style("padding: 5px")
        div.add_class("spt_table_search")
        hidden = HiddenWdg("prefix", "tile_layout")
        div.add(hidden)
        div.add_behavior( {
            'type': 'load',
            'scale_prefix':  my.scale_prefix,
            'default_scale': my.scale,
            'aspect_ratio': my.aspect_ratio,
            'cbjs_action': '''
spt.tile_layout = {}
spt.tile_layout.layout = null;

spt.tile_layout.set_layout = function(layout) {
    if (!layout.hasClass("spt_layout")) {
        layout = layout.getParent(".spt_layout");
    }
    spt.tile_layout.layout = layout;
    return layout;
}

spt.tile_layout.get_scale = function() {
    var scale_value = spt.tile_layout.layout.getElement(".spt_scale_value");
    var value = scale_value.value;
    value = parseInt(value);
    return value;
}

spt.tile_layout.set_scale = function(scale) {

    var scale_value = spt.tile_layout.layout.getElement(".spt_scale_value");
    scale_value.value = scale;

    var size_x = bvr.aspect_ratio[0]*scale/100;
    var size_y = bvr.aspect_ratio[1]*scale/100;

    //var top = bvr.src_el.getParent(".spt_tile_layout_top");
    var top = spt.tile_layout.layout;
    var els = top.getElements(".spt_tile_content");
    for (var i = 0; i < els.length; i++) {
        var el = els[i];
        el.setStyle( "width",  size_x);
        el.setStyle( "height", size_y);
    }

    var container_id = "tile_layout::scale"+bvr.scale_prefix;
    spt.container.set_value( container_id, scale);
}

spt.tile_layout.drag_start_x = null;
spt.tile_layout.drag_start_value = null;

spt.tile_layout.drag_setup = function(evt, bvr, mouse_411) {
    spt.tile_layout.set_layout(bvr.src_el);
    spt.tile_layout.drag_start_x = mouse_411.curr_x;
    var src_el = spt.behavior.get_bvr_src( bvr );
    if (!src_el.value) {
        src_el.value = 0;
    }
    spt.tile_layout.drag_start_value = src_el.value;
    src_el.focus();
    src_el.select();
}
spt.tile_layout.drag_motion = function(evt, bvr, mouse_411) {
    var start_value = spt.tile_layout.drag_start_value;
    if (isNaN(parseInt(start_value))) {
        return;
    }
    var dx = mouse_411.curr_x - spt.tile_layout.drag_start_x;
    var increment = parseInt(dx / 5);
    var multiplier;
    if (increment < 0)
        multiplier = 0.975;
    else
        multiplier = 1 / 0.975;
    increment = Math.abs(increment);
    var scale = spt.tile_layout.drag_start_value;
    for (var i = 0; i < increment; i++) {
        scale = scale * multiplier;
    }
    if (scale > 400)
        scale = 400;
    scale = parseInt(scale);
    spt.tile_layout.set_scale(scale);

}
spt.tile_layout.setup_control = function() {
   var slider = spt.tile_layout.layout.getElement('.spt_slider');
   var container_id = "tile_layout::scale"+bvr.scale_prefix;
   var initial_value = spt.container.get_value(container_id) ?  spt.container.get_value(container_id) : bvr.default_scale;

   spt.tile_layout.set_scale(initial_value);
   new Slider(slider, slider.getElement('.knob'), {
    range: [30, 400],
    steps: 74,
    initialStep: initial_value,
    onChange: function(value){
      if (value) spt.tile_layout.set_scale(value);
    }
  });
}

        ''' } )

        div.add_behavior( {
        'type': 'load',
        'cbjs_action': '''
        spt.tile_layout.set_layout(bvr.src_el);

        spt.tile_layout.setup_control();

        '''
        } )

        table = Table()
        div.add(table)
        table.add_row()

        """
        # TO BE DELETED
        less_div = DivWdg()
        less_div.add("<input type='button' value='<<'/>")
        table.add_cell(less_div)

        less_div.add_behavior( {
            'type': 'click_up',
            'cbjs_action': '''
            spt.tile_layout.set_layout(bvr.src_el);
            var scale = spt.tile_layout.get_scale();
            scale = scale * 0.95;
            scale = parseInt(scale);
            spt.tile_layout.set_scale(scale);
            '''
        } )
        """

        dark_color = div.get_color("background", -5)
        light_color = div.get_color('color')
        med_color = div.get_color('color2')

        slider_div = DivWdg(css='spt_slider')
        slider_div.add_styles('valign: bottom; background: %s; height: 6px; width: 200px;'% light_color)
        knob_div = DivWdg(css='knob')
        knob_div.add_behavior({'type':'click',
                'cbjs_action': 'spt.tile_layout.set_layout(bvr.src_el)'
                })
        knob_div.add_styles('background: %s; bottom: 4px;\
                height: 16px; width: 12px; border-radius: 6px 6px 0 0;\
                border: 1px %s solid'\
                %(dark_color, med_color ))
        slider_div.add(knob_div)
        td = table.add_cell(slider_div)
        value_wdg = TextWdg("scale")
        value_wdg.add_class("spt_scale_value")
        td = table.add_cell(value_wdg)
        td.add(" %")

        td.add_style("padding: 3px 8px")

        """
        # TO BE DELETED
        from tactic.ui.filter import FilterData
        filter_data = FilterData.get()
        data_list = filter_data.get_values_by_prefix("tile_layout")
        if data_list:
            data = data_list[0]
        else:
            data = {}
        my.scale = data.get("scale")
        if my.scale == None:
            my.scale = my.kwargs.get("scale")
        """
        if my.scale:
            value_wdg.set_value(my.scale)
        value_wdg.add_style("width: 24px")
        value_wdg.add_style("text-align: center")
        value_wdg.add_behavior( {
        'type': 'change',
        'cbjs_action': '''
        var value = bvr.src_el.value;
        var scale = parseInt(value);
        spt.tile_layout.set_layout(bvr.src_el);
        spt.tile_layout.set_scale(scale);
        '''
        } )
        value_wdg.add_behavior( {
        'type': 'load',
        'cbjs_action': '''
        var value = bvr.src_el.value;
        if (!value) {
            value = 100;
        }
        var scale = parseInt(value);
        spt.tile_layout.set_layout(bvr.src_el);
        spt.tile_layout.set_scale(scale);
        '''
        } )

        value_wdg.add_behavior( {
            'type': 'smart_drag',
            'bvr_match_class': 'spt_scale_value',
            'ignore_default_motion' : True,
            "cbjs_setup": 'spt.tile_layout.drag_setup( evt, bvr, mouse_411 );',
            "cbjs_motion": 'spt.tile_layout.drag_motion( evt, bvr, mouse_411 );'
        } )

        """
        # TO BE DELETED
        more_div = DivWdg()
        more_div.add("<input type='button' value='>>'/>")
        table.add_cell(more_div)

        more_div.add_behavior( {
            'type': 'click_up',
            'cbjs_action': '''
            spt.tile_layout.set_layout(bvr.src_el);
            var scale = spt.tile_layout.get_scale();
            scale = scale / 0.95;
            scale = parseInt(scale);
            spt.tile_layout.set_scale(scale);
            '''
        } )

        """

        return div

    def get_title(my, sobject):
        div = DivWdg()

        div.add_class("spt_tile_title")

        div.add_color("background", "background3")
        div.add_style("padding: 5px")
        div.add_style("height: 16px")

        detail_div = DivWdg()
        div.add(detail_div)
        detail_div.add_class("spt_tile_detail")
        detail_div.add_style("float: right")
        detail_div.add_style("margin-top: -2px")

        detail = IconButtonWdg(title="Detail", icon=IconWdg.ZOOM)
        detail_div.add(detail)

        header_div = DivWdg()
        header_div.add_class("spt_tile_select")
        header_div.add_class("hand")
        div.add(header_div)
        header_div.add_class("SPT_DTS")
        header_div.add_style("overflow-x: hidden")

        from pyasm.widget import CheckboxWdg
        checkbox = CheckboxWdg("select")
        checkbox.add_class("spt_tile_checkbox")

        title = sobject.get_name()
        if not title:
            title = sobject.get_code()

        table = Table()
        header_div.add(table)
        header_div.add_style("position: relative")

        table.add_cell(checkbox)

        title_div = DivWdg()
        td = table.add_cell(title_div)
        title_div.add(title)
        title_div.add_style("height: 15px")
        title_div.add_style("left: 25px")
        title_div.add_style("top: 3px")
        title_div.add_style("position: absolute")
        title_div.add_attr("title", title)
        #title_div.add_style("white-space", "nowrap")
        #td.add_style("overflow: hidden")
        title_div.add("
")

        description = sobject.get_value("description", no_exception=True)
        if description:
            div.add_attr("title", sobject.get_code())

        return div

from pyasm.biz import Snapshot
from pyasm.web import HtmlElement
__all__.append("ThumbWdg2")
class ThumbWdg2(BaseRefreshWdg):

    def init(my):
        my.path = None

    def set_sobject(my, sobject):
        super(ThumbWdg2, my).set_sobject(sobject)
        my.path = my.get_path_from_sobject(sobject)

    def set_path(my, path):
        my.path = path

    def get_path(my):
        return my.path

    def get_display(my):

        width = "100%"
        height = "100%"

        sobject = my.get_current_sobject()

        div = DivWdg()
        div.add_class("spt_thumb_top")

        path = my.path
        if path:
            img = HtmlElement.img(src=path)
        else:
            search_type = sobject.get_search_type_obj()
            path = my.get_path_from_sobject(search_type)
            if path:
                img = DivWdg()
                img.add_style("opacity: 0.2")

                img_inner = HtmlElement.img(src=path)
                img.add(img_inner)

                img_inner.add_style("width: %s" % width)

        if path and path.startswith("/context"):
            img.add_style("padding: 10px 15%")
            img.add_style("width: 70%")
        elif path:
            img.add_style("width: %s" % width)
            img.add_style("height: %s" % height)
            img.add_style('margin-left','auto')
            img.add_style('margin-right','auto')

        if not path:
            img = DivWdg()
        img.add_class("spt_image")
        div.add(img)

        div.add_style("height: 100%")

        return div

    def get_path_from_sobject(my, sobject):

        icon_path = None
        path = None

        search_type = sobject.get_search_type()
        search_code = sobject.get_value("code", no_exception=True)
        if not search_code:
            search_code = sobject.get_id()

        # FIXME: make this faster

        snapshot = Snapshot.get_snapshot(search_type, search_code, process=['icon','publish',''])

        if snapshot:
            file_type = "web"
            icon_path = snapshot.get_web_path_by_type(file_type)

            file_type = "main"
            path = snapshot.get_web_path_by_type(file_type)

        if icon_path:
            path = icon_path
        elif path:
            path = my.find_icon_link(path)

        return path

    def find_icon_link(my, file_path, repo_path=None):
        from pyasm.widget import ThumbWdg
        return ThumbWdg.find_icon_link(file_path, repo_path)


import random
from PyFakeDados.CONSTANTS import *
from PyFakeDados.logradouro import gerar_logradouro, gerar_logradouro_com_numero, gerar_numero
from PyFakeDados.bairro import gerar_bairro
from PyFakeDados.cep import gerar_cep
from PyFakeDados.municipio import gerar_municipio
from PyFakeDados.estado import gerar_estado, gerar_uf, busca_nome_uf
from PyFakeDados.utils import remover_acentos

def gerar_endereco(uf=None, force_ASCII=False, force_upper=False):

    endereco = {}

    if uf is None:
        uf = gerar_uf()

    logradouro = gerar_logradouro()
    numero = gerar_numero()
    bairro = gerar_bairro()
    estado = busca_nome_uf(uf)
    municipio = gerar_municipio(uf=uf)
    cep = gerar_cep(uf=uf)

    endereco["uf"] = uf
    endereco["estado"] = estado
    endereco["municipio"] = municipio
    endereco["cep"] = cep
    endereco["bairro"] = bairro
    endereco["logradouro"] = logradouro
    endereco["numero"] = numero

    if force_ASCII:
        for i in endereco:
            if isinstance(endereco[i], str):
                endereco[i] = remover_acentos(endereco[i])

    if force_upper:
        for i in endereco:
            if isinstance(endereco[i], str):
                endereco[i] = endereco[i].upper()

    return endereco


import kmeans
import numpy as np
from sklearn.preprocessing import normalize
import helper as hp
import random

# activity vectors as differences between subsequent states
def find_activity_vectors(data_points):
    activity_vectors = []
    for i in range(len(data_points) - 1):
        activity = data_points[i + 1] - data_points[i]
        activity_vectors.append(activity.tolist())
    return activity_vectors

# state_indices - vector of data length where each element is index of closest prototypical state
# action_indices - vector of data length where each element is index of closest prototypical activity
def find_probability_matrix(state_indices, action_indices, s_centers, a_centers):
    matrix = np.zeros((len(s_centers), len(a_centers)))
    for i in range(len(action_indices)):  # sum up activity prototypes and state prototypes occurring together
        s_i = state_indices[i]
        r_j = action_indices[i]
        matrix[s_i][r_j] += 1
    probability_matrix = matrix / np.sum(matrix)  # normalize - divide by sum of all elements
    # probability_matrix = normalize(matrix,norm='l1')
    return probability_matrix

def generate_path(probability_matrix, state_prototypes, action_prototypes, state_indices, iterations):
    state_index = random.sample(state_indices, 1)[0]  # select random point
    path = []
    current_position = state_prototypes[state_index]  # choose closest state prototype
    for i in range(iterations):
        path.append(current_position)
        # following should not be the case but who knows what is going on with 2nd map
        if np.sum(probability_matrix[state_index]) == 0:
            best_action_index = np.argmax((probability_matrix[state_index]))
        else:
            # choose best action using matrix of joint probabilities
            best_action_index = np.argmax((probability_matrix[state_index] / np.sum(probability_matrix[state_index])))
        best_action = action_prototypes[best_action_index]
        current_position = current_position + best_action
        dist = [kmeans.distance(current_position, k) for k in state_prototypes]
        min_index, = np.where(dist == np.min(dist))  # choose closest prototype
        state_index = min_index[0]
    return path

def run_bayesian_learning(points_filename, som_centers_filename, activity_centers_num, path_iterations_num):
    data_points = hp.read_points(points_filename)
    activity_vectors = np.array(find_activity_vectors(data_points))
    # prototypical activities - centers of clusters of activities
    # prototypical_activities - vector of data length where each element is index of closest prototypical activity
    activity_indices, prototypical_activities = kmeans.kmeans(activity_centers_num, activity_vectors)
    prototypical_states = hp.read_points(som_centers_filename)
    # e-step assigns each state to the closest prototypical state
    # prototypical_states - vector of data length where each element is index of closest prototypical state
    state_indices = kmeans.e_step(prototypical_states, data_points)
    probability_matrix = find_probability_matrix(state_indices, activity_indices, prototypical_states,
                                                 prototypical_activities)
    path = np.array(
        generate_path(probability_matrix, prototypical_states, prototypical_activities, state_indices,
                      path_iterations_num))
    return path


import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

c1 = [50.0]
c2 = [25.0]
c3 = [0.0]
kl = 0.025
k2 = 0.01
time_difference = 0.1
t = 0.0
last_time = 15.0
i = 0

fig, ax = plt.subplots()
line_c1, = ax.plot([], [], label='C1')
line_c2, = ax.plot([], [], label='C2')
line_c3, = ax.plot([], [], label='C3')
ax.set_xlim(0, int(last_time / time_difference))
ax.set_ylim(0, max(max(c1), max(c2), max(c3)) + 5)
ax.set_xlabel('Time')
ax.set_ylabel('Concentration')
ax.set_title('Chemical Reaction Simulation')
ax.legend()

def init():
    line_c1.set_data([], [])
    line_c2.set_data([], [])
    line_c3.set_data([], [])
    return line_c1, line_c2, line_c3

def animate(frame):
    global t, i, time_difference

    if t <= last_time:
        c1_next = c1[i] + (k2 * c3[i] - kl * c1[i] * c2[i]) * time_difference
        c2_next = c2[i] + (k2 * c3[i] - kl * c1[i] * c2[i]) * time_difference
        c3_next = c3[i] + 2.0 * (kl * c1[i] * c2[i] - k2 * c3[i]) * time_difference

        c1.append(c1_next)
        c2.append(c2_next)
        c3.append(c3_next)

        i += 1
        t += time_difference

        if t >= 2.0:
            time_difference = 0.2
        if t == 6.0:
            time_difference = 0.4

    line_c1.set_data(range(len(c1)), c1)
    line_c2.set_data(range(len(c2)), c2)
    line_c3.set_data(range(len(c3)), c3)
    return line_c1, line_c2, line_c3

ani = FuncAnimation(fig, animate, frames=int(last_time / time_difference),
                    init_func=init, blit=True, interval=200)

plt.show()


import time
import requests
from bs4 import BeautifulSoup

def spider():
    url = "http://www.naver.com"
    source_code = requests.get(url)
    plain_text = source_code.text
    soup = BeautifulSoup(plain_text, 'lxml')

    ranks = soup.find("div", {"class": "rankup"})

    for keyword in ranks.findAll('li'):
        print(keyword.a['title'])

def funcTimer(count):
    while 0 < count:
        time.sleep(1)
        print(time.strftime("%Y-%m-%d %H:%M", time.localtime()))
        spider()
        print()
        count -= 1

funcTimer(3)
#spider()


from __future__ import annotations

import sys
import warnings
from argparse import Action
from functools import wraps
from types import ModuleType
from typing import Any, Callable

from packaging.version import Version, parse

from . import __version__

class DeprecatedError(RuntimeError):
    pass

# inspired by deprecation (https://deprecation.readthedocs.io/en/latest/) and
# CPython's warnings._deprecated
class DeprecationHandler:
    _version: Version

    def __init__(self, version: Version | str):
        """Factory to create a deprecation handle for the specified version.

        :param version: The version to compare against when checking deprecation statuses.
        """
        try:
            self._version = parse(version)
        except TypeError:
            self._version = parse("0.0.0.dev0+placeholder")

    def __call__(
        self,
        deprecate_in: str,
        remove_in: str,
        *,
        addendum: str | None = None,
        stack: int = 0,
    ) -> Callable[(Callable), Callable]:
        """Deprecation decorator for functions, methods, & classes.

        :param deprecate_in: Version in which code will be marked as deprecated.
        :param remove_in: Version in which code is expected to be removed.
        :param addendum: Optional additional messaging. Useful to indicate what to do instead.
        :param stack: Optional stacklevel increment.
        """

        def deprecated_decorator(func: Callable) -> Callable:
            # detect function name and generate message
            category, message = self._generate_message(
                deprecate_in,
                remove_in,
                f"{func.__module__}.{func.__qualname__}",
                addendum=addendum,
            )

            # alert developer that it's time to remove something
            if not category:
                raise DeprecatedError(message)

            # alert user that it's time to remove something
            @wraps(func)
            def inner(*args, **kwargs):
                warnings.warn(message, category, stacklevel=2 + stack)

                return func(*args, **kwargs)

            return inner

        return deprecated_decorator

    def argument(
        self,
        deprecate_in: str,
        remove_in: str,
        argument: str,
        *,
        rename: str | None = None,
        addendum: str | None = None,
        stack: int = 0,
    ) -> Callable[(Callable), Callable]:
        """Deprecation decorator for keyword arguments.

        :param deprecate_in: Version in which code will be marked as deprecated.
        :param remove_in: Version in which code is expected to be removed.
        :param argument: The argument to deprecate.
        :param rename: Optional new argument name.
        :param addendum: Optional additional messaging. Useful to indicate what to do instead.
        :param stack: Optional stacklevel increment.
        """

        def deprecated_decorator(func: Callable) -> Callable:
            # detect function name and generate message
            category, message = self._generate_message(
                deprecate_in,
                remove_in,
                f"{func.__module__}.{func.__qualname__}({argument})",
                # provide a default addendum if renaming and no addendum is provided
                addendum=f"Use '{rename}' instead."
                if rename and not addendum
                else addendum,
            )

            # alert developer that it's time to remove something
            if not category:
                raise DeprecatedError(message)

            # alert user that it's time to remove something
            @wraps(func)
            def inner(*args, **kwargs):
                # only warn about argument deprecations if the argument is used
                if argument in kwargs:
                    warnings.warn(message, category, stacklevel=2 + stack)

                    # rename argument deprecations as needed
                    value = kwargs.pop(argument, None)
                    if rename:
                        kwargs.setdefault(rename, value)

                return func(*args, **kwargs)

            return inner

        return deprecated_decorator

    def action(
        self,
        deprecate_in: str,
        remove_in: str,
        action: Action,
        *,
        addendum: str | None = None,
        stack: int = 0,
    ):
        class DeprecationMixin:
            def __init__(inner_self, *args, **kwargs):
                super().__init__(*args, **kwargs)

                category, message = self._generate_message(
                    deprecate_in,
                    remove_in,
                    (
                        # option_string are ordered shortest to longest,
                        # use the longest as it's the most descriptive
                        f"`{inner_self.option_strings[-1]}`"
                        if inner_self.option_strings
                        # if not a flag/switch, use the destination itself
                        else f"`{inner_self.dest}`"
                    ),
                    addendum=addendum,
                )

                # alert developer that it's time to remove something
                if not category:
                    raise DeprecatedError(message)

                inner_self.category = category
                inner_self.help = message

            def __call__(inner_self, parser, namespace, values, option_string=None):
                # alert user that it's time to remove something
                warnings.warn(
                    inner_self.help, inner_self.category, stacklevel=7 + stack
                )

                super().__call__(parser, namespace, values, option_string)

        return type(action.__name__, (DeprecationMixin, action), {})

    def module(
        self,
        deprecate_in: str,
        remove_in: str,
        *,
        addendum: str | None = None,
        stack: int = 0,
    ) -> None:
        """Deprecation function for modules.

        :param deprecate_in: Version in which code will be marked as deprecated.
        :param remove_in: Version in which code is expected to be removed.
        :param addendum: Optional additional messaging. Useful to indicate what to do instead.
        :param stack: Optional stacklevel increment.
        """
        self.topic(
            deprecate_in=deprecate_in,
            remove_in=remove_in,
            topic=self._get_module(stack)[1],
            addendum=addendum,
            stack=2 + stack,
        )

    def constant(
        self,
        deprecate_in: str,
        remove_in: str,
        constant: str,
        value: Any,
        *,
        addendum: str | None = None,
        stack: int = 0,
    ) -> None:
        """Deprecation function for module constant/global.

        :param deprecate_in: Version in which code will be marked as deprecated.
        :param remove_in: Version in which code is expected to be removed.
        :param constant:
        :param value:
        :param addendum: Optional additional messaging. Useful to indicate what to do instead.
        :param stack: Optional stacklevel increment.
        """
        # detect calling module
        module, fullname = self._get_module(stack)
        # detect function name and generate message
        category, message = self._generate_message(
            deprecate_in,
            remove_in,
            f"{fullname}.{constant}",
            addendum,
        )

        # alert developer that it's time to remove something
        if not category:
            raise DeprecatedError(message)

        # patch module level __getattr__ to alert user that it's time to remove something
        super_getattr = getattr(module, "__getattr__", None)

        def __getattr__(name: str) -> Any:
            if name == constant:
                warnings.warn(message, category, stacklevel=2 + stack)
                return value

            if super_getattr:
                return super_getattr(name)

            raise AttributeError(f"module '{fullname}' has no attribute '{name}'")

        module.__getattr__ = __getattr__

    def topic(
        self,
        deprecate_in: str,
        remove_in: str,
        *,
        topic: str,
        addendum: str | None = None,
        stack: int = 0,
    ) -> None:
        """Deprecation function for a topic.

        :param deprecate_in: Version in which code will be marked as deprecated.
        :param remove_in: Version in which code is expected to be removed.
        :param topic: The topic being deprecated.
        :param addendum: Optional additional messaging. Useful to indicate what to do instead.
        :param stack: Optional stacklevel increment.
        """
        # detect function name and generate message
        category, message = self._generate_message(
            deprecate_in, remove_in, topic, addendum
        )

        # alert developer that it's time to remove something
        if not category:
            raise DeprecatedError(message)

        # alert user that it's time to remove something
        warnings.warn(message, category, stacklevel=2 + stack)

    def _get_module(self, stack: int) -> tuple[ModuleType, str]:
        """Detect the module from which we are being called.

        :param stack: The stacklevel increment.
        :return: The module and module name.
        """
        import inspect  # expensive

        try:
            frame = sys._getframe(2 + stack)
            module = inspect.getmodule(frame)
            return (module, module.__name__)
        except (IndexError, AttributeError):
            raise DeprecatedError("unable to determine the calling module") from None

    def _generate_message(
        self, deprecate_in: str, remove_in: str, prefix: str, addendum: str
    ) -> tuple[type[Warning] | None, str]:
        """Deprecation decorator for functions, methods, & classes.

        :param deprecate_in: Version in which code will be marked as deprecated.
        :param remove_in: Version in which code is expected to be removed.
        :param prefix: The message prefix, usually the function name.
        :param addendum: Additional messaging. Useful to indicate what to do instead.
        :return: The warning category (if applicable) and the message.
        """
        deprecate_version = parse(deprecate_in)
        remove_version = parse(remove_in)

        if self._version < deprecate_version:
            category = PendingDeprecationWarning
            warning = f"is pending deprecation and will be removed in {remove_in}."
        elif self._version < remove_version:
            category = DeprecationWarning
            warning = f"is deprecated and will be removed in {remove_in}."
        else:
            category = None
            warning = f"was slated for removal in {remove_in}."

        return (
            category,
            " ".join(filter(None, [prefix, warning, addendum])),  # message
        )

deprecated = DeprecationHandler(__version__)


#!/usr/bin/python3

import argparse
import yaml
import base_benchmark
import time
import subprocess
import sys

class timed_command(base_benchmark.base_benchmark):
    def __init__(self):
        base_benchmark.base_benchmark.__init__(self)
        self.name = __class__.__name__

    def run_benchmark(self):
        print("running " + self.get_name())
        print(self.settings)
        if "threads" in self.settings.keys():
            threads = self.settings['threads']
        else:
            threads = 32
        command = self.settings['command'].format(threads=threads, output=self.settings['output'])
        start = time.time()
        with subprocess.Popen(command, stdout=sys.stderr, stderr=subprocess.PIPE, universal_newlines=True, shell=True) as process:
                _, stderr = process.communicate()
                if process.returncode != 0:
                    print(stderr.splitlines()[:-1], file=sys.stderr)
                    print("fucked it.")
        end = time.time() - start
        print(end)
        return end


import numpy as np

class big_num(object):
    np.set_printoptions(suppress=True)

    def __init__(self, num, n, sign) -> None:
        self.num = num
        self.n = n
        self.sign = sign

    # Functions for conversions

    # convert number strings into numpy array, the form of big number
    def write_num_into_vector(num_str, n=0):
        if num_str[0] == '-':
            sign = '-'
            num_str = num_str[1:len(num_str)]
        else: sign = '+'
        if n == 0 or n == 1:
            res = np.array([int(num) for num in num_str])
        else:
            l = len(num_str)
            k = l % n
            if k!= 0:res = [int(str(num_str[0:k]))]
            else: res = []
            for i in range(k, len(num_str),n):
                res.append(int(num_str[i:i+n]))
            res = np.array(res)
        return big_num(res, n, sign)

    def write_num_into_str(num):
        if num.sign == '-': res = '-'
        else: res = '+'
        n = num.n
        v = num.num
        v = v.astype(int)
        for i in range(len(v)):
            if i > 0:
                temp = str(v[i])
                if len(temp) == n:
                    res += temp
                else:
                    res += temp.zfill(n)
            else: res += str(v[0])
        return res

    # Functions for comparisons

    def equal(num_a, num_b):
        if num_a.sign == num_b.sign and np.array_equal(num_a.num, num_b.num):
            return True
        if np.array_equal(num_a.num, np.zeros(1)) and np.array_equal(num_b.num, np.zeros(1)):
            return True
        return False

    def larger(num_a, num_b):
        if big_num.equal(num_a, num_b):
            return False

        a, b, s_a, s_b = num_a.num, num_b.num, num_a.sign, num_b.sign
        l_a, l_b = len(a), len(b)
        if s_a == '+' and s_b == '-': return True
        if s_a == '+' and s_b == '+':
            if l_a > l_b: return True
            elif l_a < l_b: return False
            else:
                for i in range(l_a):
                    if a[i] > b[i]: return True
                    elif a[i] < b[i]: return False
        if s_a == '-' and s_b == '-':
            if l_a > l_b: return False
            elif l_a < l_b: return True
            else:
                for i in range(l_a):
                    if a[i] > b[i]: return False
                    elif a[i] < b[i]: return True
        return False

    def smaller(num_a, num_b):
        if big_num.equal(num_a, num_b): return False
        if big_num.larger(num_a, num_b): return False
        return True

    # Functions for mathematical operations

    def addition(num_a, num_b):
        if num_a.n != num_b.n:
            raise ValueError("The big numbers are in different element length representations",(num_a.n,num_b.n))
        # a + b = res
        if (num_a.sign == '+' and num_b.sign == '+') or (num_a.sign == '-' and num_b.sign == '-'):
            l1, l2, a, b = len(num_a.num), len(num_b.num), num_a.num, num_b.num
            if(l1 > l2): b = np.hstack((np.zeros(l1-l2), b)) # add paddings to make two array
            elif(l2 > l1): a = np.hstack((np.zeros(l2-l1), a)) # has equal length
            res = a + b
            i, carry, n = len(res)-1, 0, 10**num_a.n
            while(True):
                res[i] += carry
                if res[i] >= n:
                    res[i] -= n
                    carry = 1
                else: carry = 0
                if i == 0:
                    if carry == 1:
                        res = np.hstack((np.ones((1)),res))
                    break
                i -= 1
            return big_num(res, num_a.n, num_a.sign)
        if num_a.sign == '+' and num_b.sign == '-':
            temp = big_num(num_b.num, num_b.n, '+')
        if num_a.sign == '-' and num_b.sign == '+':
            temp = big_num(num_b.num, num_b.n, '-')
        return big_num.subtract(num_a, temp)

    def subtract(num_a, num_b):
        if num_a.n != num_b.n:
            raise ValueError("The big numbers are in different element length representations",(num_a.n,num_b.n))
        if (num_a.sign == '+' and num_b.sign == '+') or (num_a.sign == '-' and num_b.sign == '-'):
            temp_1, temp_2 = big_num(num_a.num, num_a.n, '+'), big_num(num_b.num, num_b.n, '+')
            if big_num.smaller(temp_1, temp_2):
                if num_a.sign == '+': sign = '-'
                else: sign = '+'
                l1, l2, a, b = len(num_b.num), len(num_a.num), num_b.num, num_a.num
            else:
                sign = num_a.sign
                l1, l2, a, b = len(num_a.num), len(num_b.num), num_a.num, num_b.num
            if(l1 > l2): b = np.hstack((np.zeros(l1-l2), b)) # add paddings to make two array
            elif(l2 > l1): a = np.hstack((np.zeros(l2-l1), a))
            res = a - b
            i, carry, n = len(res)-1, 0, 10**num_a.n
            while(True):
                res[i] += carry
                if res[i] < 0:
                    res[i] = n + res[i]
                    carry = -1
                else: carry = 0
                if i == 0:
                    # if carry == -1:
                    #     res = np.hstack((np.ones((1)),res))
                    break
                i -= 1
            return big_num(res, num_a.n, sign)
        if num_a.sign == '+' and num_b.sign == '-':
            temp = big_num(num_b.num, num_b.n, '+')
        if num_a.sign == '-' and num_b.sign == '+':
            temp = big_num(num_b.num, num_b.n, '-')
        return big_num.addition(num_a, temp)

    def multiplication(num_a, num_b):
        if num_a.n != num_b.n:
            raise ValueError("The big numbers are in different element length representations",(num_a.n,num_b.n))
        if (num_a.sign == '+' and num_b.sign == '+') or (num_a.sign == '-' and num_b.sign == '-'): sign = '+'
        else: sign = '-'
        l1, l2, a, b = len(num_a.num), len(num_b.num), num_a.num, num_b.num
        table = []
        for i in range(l1):
            temp = []
            for j in range(l2):
                temp.append(a[i] * b[j])
            for _ in range(l1-i-1):
                temp.append(0)
            table.append(np.asarray(temp))
        max_l = len(table[0]) + 1
        table = np.asarray(table,dtype=object)
        i = len(table)-1
        new_table = []
        while(True): # add paddings to the left of every row
            if i < 0: break
            new_table.append(np.hstack((np.zeros(max_l-len(table[i])), table[i])))
            i -= 1
        new_table = np.asarray(new_table)
        res = np.sum(new_table, axis = 0)
        i, carry, n= len(res)-1, 0, 10**num_a.n
        while(True): # compute carry and reform the number
            if i < 0: break
            res[i] += carry
            carry = res[i] - (res[i]%n)
            res[i] -= carry
            carry /= n
            i -= 1
        if int(res[0]) == 0: res = np.delete(res, 0)
        return big_num(res, num_a.n, sign)

    def division(num_a, num_b):
        if num_a.n != num_b.n:
            raise ValueError("The big numbers are in different element length representations",(num_a.n,num_b.n))
        if int(big_num.write_num_into_str(num_b)) == 0:
            raise ValueError("Error: Divisor = 0.")
        if (num_a.sign == '+' and num_b.sign == '+') or (num_a.sign == '-' and num_b.sign == '-'): sign = '+'
        else: sign = '-'
        l1, l2, a, b = len(num_a.num), len(num_b.num), num_a.num, num_b.num
        if big_num.equal(big_num(a, num_a.n, '+'), big_num(b, num_b.n, '+')):
            return [big_num(np.ones(1), num_a.n, sign), big_num(np.zeros(1), num_a.n, num_a.sign)]
        elif big_num.smaller(big_num(a, num_a.n, '+'), big_num(b, num_b.n, '+')):
            return [big_num(np.zeros(1), num_a.n, num_a.sign), num_a]
        # start actual division from here
        # idea, dividend subtract multiples of divisors,
        # start from n = 10000, where n * divisor
        # gradually decrease n, by dividing by 10 until n = 1.
        n, res = 10000, 0
        temp_a = big_num(a, num_a.n, '+')
        while(True):
            print(123456)#------------------------------test--------------------------------------
            temp = big_num.write_num_into_vector(str(int(n)), num_a.n)
            sub = big_num.multiplication(temp, big_num(b, num_b.n, '+'))
            if big_num.smaller(sub, temp_a) or big_num.equal(sub, temp_a):
                temp_a = big_num.subtract(temp_a, sub)
                res += n
            elif big_num.larger(sub, temp_a) and n > 1:
                n /= 10
            if (big_num.equal(temp_a, big_num.write_num_into_vector('0'))):
                print(1234567)#------------------------------test--------------------------------------
                break
            if (n == 1 and big_num.smaller(temp_a, big_num(b, num_b.n, '+'))):
                print(12345678)#------------------------------test--------------------------------------
                break
            print(res)
        res = big_num.write_num_into_vector(str(int(res)))
        return [big_num(res.num, res.n, sign), big_num(temp_a.num, temp_a.n, num_a.sign)]

print('enter first num:')
temp_num1 = '+32'
print('enter second num:')
temp_num2 = '-8'
num_1 = big_num.write_num_into_vector(temp_num1,4)
print('num_1 = ', temp_num1)
print(num_1.num)
num_2 = big_num.write_num_into_vector(temp_num2,4)
print('num_2 = ', temp_num2)
print(num_2.num)
# print(temp_num2)
# print(num_2.num)
# num_sum = big_num.addition(num_1, num_2)
# print(num_sum.num)
# num_sum_str = big_num.write_num_into_str(num_sum)
# print(num_sum_str)
# print(big_num.equal(num_1, num_2))
# print(big_num.larger(num_1, num_2))
# print(big_num.smaller(num_1, num_2))
# num_sub = big_num.subtract(num_2, num_1)
# print(num_sub.num)

# print(big_num.write_num_into_str(big_num.subtract(num_1, num_2)))
# print(big_num.write_num_into_str(big_num.subtract(num_2, num_1)))
# print(big_num.write_num_into_str(big_num.addition(num_1, num_2)))
# print(big_num.write_num_into_str(big_num.addition(num_2, num_1)))
# print(big_num.write_num_into_str(big_num.multiplication(num_1, num_2)))
# print(big_num.write_num_into_str(big_num.multiplication(num_2, num_1)))
res = big_num.division(num_1, num_2)
print(big_num.write_num_into_str(res[0]),',',big_num.write_num_into_str(res[1]))
print("-----------------------------------------------------------------")

# print(int(temp_num1)-int(temp_num2))
# print(int(temp_num2)-int(temp_num1))
# print(int(temp_num2)+int(temp_num1))
# print(int(temp_num1)+int(temp_num2))
# print(int(temp_num1)*int(temp_num2))
# print(int(temp_num2)*int(temp_num1))
# print(int(temp_num1)/int(temp_num2))

# 已完成
# 字符转数字，数字转字符
# 大小比较函数
# 加减乘除


'''
Authors - Andrew Vo & Anant Natekar
'''
import nltk
import os
import re
import random
import string
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn import metrics
from sklearn import datasets
from sklearn.cluster import KMeans, AgglomerativeClustering

#path = "/Users/nat2147/Anant/code/python/" #defining the path to the training data files
#feature_vectors = load_svmlight_file(path + "trainingdatafile.txt")
iris = datasets.load_iris()
feature_vectors = iris['data']
classification_labels = iris['target']

#kmeans clustering
sc = []
nmi = []
for number_of_clusters in range (2, 26):
    km = KMeans(number_of_clusters).fit(feature_vectors)
    clustering_labels = km.labels_
    sc.append(metrics.silhouette_score(feature_vectors, clustering_labels, metric='euclidean'))
    nmi.append(metrics.normalized_mutual_info_score(classification_labels, clustering_labels))

plt.title("K Means Clustering", fontsize=15)
plt.plot(sc, color='b', linestyle='-', linewidth=2, label = "Sihouette Coefficient")
plt.plot(nmi, color='g', linestyle='-', linewidth=2, label = "Normalized Mutual Information")
plt.xlabel("Number of Clusters",fontsize=13)
plt.ylabel("Measures",fontsize=13)
plt.legend(loc = 1)
#plt.show(block=False)
plt.show()

#hierarchical (Agglomerative) clustering
for number_of_clusters in range (2, 26):
    single_linkage_model = AgglomerativeClustering(
        n_clusters=number_of_clusters, linkage='ward').fit(feature_vectors)
    clustering_labels = single_linkage_model.labels_
    sc.append(metrics.silhouette_score(feature_vectors, clustering_labels, metric='euclidean'))
    nmi.append(metrics.normalized_mutual_info_score(classification_labels, clustering_labels))

plt.title("Hierarchical Clustering", fontsize=15)
plt.plot(sc, color='b', linestyle='-', linewidth=2, label = "Sihouette Coefficient")
plt.plot(nmi, color='g', linestyle='-', linewidth=2, label = "Normalized Mutual Information")
plt.xlabel("Number of Clusters",fontsize=13)
plt.ylabel("Measures",fontsize=13)
plt.legend(loc = 1)
#plt.show(block=False)
plt.show()


r"""
Solve Poisson equation on (0, 2pi)x(0, 2pi) with periodic bcs

    \nabla^2 u = f, u(2pi, y) = u(0, y), u(x, 2pi) = u(x, 0)

Use Fourier basis and find u in VxV such that

    (v, div(grad(u))) = (v, f)    for all v in VxV

where V is the Fourier basis span{exp(1jkx)}_{k=-N/2}^{N/2-1} and
VxV is a tensorproductspace.

"""
from sympy import Symbol, cos, sin, exp, lambdify
import numpy as np
import os
from shenfun.fourier.bases import R2CBasis, C2CBasis
from shenfun.tensorproductspace import TensorProductSpace
from shenfun import inner, div, grad, TestFunction, TrialFunction, Function, Array
from mpi4py import MPI
try:
    import matplotlib.pyplot as plt
except:
    plt = None

comm = MPI.COMM_WORLD

# Use sympy to compute a rhs, given an analytical solution
x = Symbol("x")
y = Symbol("y")
ue = cos(4*x) + sin(8*y)
fe = ue.diff(x, 2) + ue.diff(y, 2)

ul = lambdify((x, y), ue, 'numpy')
fl = lambdify((x, y), fe, 'numpy')

# Size of discretization
N = (32, 45)

K0 = C2CBasis(N[0])
K1 = R2CBasis(N[1])
T = TensorProductSpace(comm, (K0, K1))
X = T.local_mesh(True) # With broadcasting=True the shape of X is local_shape, even though the number of datapoints are still the same as in 1D
u = TrialFunction(T)
v = TestFunction(T)

# Get f on quad points
fj = fl(*X)

# Compute right hand side
f_hat = inner(v, fj)

# Solve Poisson equation
#A = inner(v, div(grad(u)))
A = inner(grad(v), grad(u))
f_hat = A.solve(-f_hat)

uq = Array(T, False)
uq = T.backward(f_hat, uq, fast_transform=True)

uj = ul(*X)
assert np.allclose(uj, uq)

if not plt is None and not 'pytest' in os.environ:
    plt.figure()
    plt.contourf(X[0], X[1], uq)
    plt.colorbar()

    plt.figure()
    plt.contourf(X[0], X[1], uj)
    plt.colorbar()

    plt.figure()
    plt.contourf(X[0], X[1], uq-uj)
    plt.colorbar()
    plt.title('Error')
    plt.show()